push_back() and vector of classes - C++ newbie :)

A

Avi Bercovich

Hello everybody,

I;m doing my first bits of programming with C++ using the STL. After
falling in love with the map<> container I;m now getting a little
annoyed with its mate vector<>. Using vector with the built-in types
like string and int 'm fine, but I dont understand how to declare/use a
vector filled with my own classes.

I'm obviously not understanding at all how to copy C++ objects. If
somebody would be so kind as to explain what I need to do to store my
homebrew classes in a vector container I;d be very grateful.

grts,

avi


Here's and edited for brevity version of my code and the error that
MIPSpro gives me.

------

class Device {

public:

Device(string ID, string Type, int maxSpeed=0);
~Device();

// boring getX()/setX() methods cut

private:

string _ID;
string _type;

};


Device::Device(string ID, string Type, int maxSpeed) {

_ID = ID;
_type = Type;

}


Device::Device(const Device& device) {

_ID = device._ID;
_type = device._type;

}



class Writer {

public:

Writer();
~Writer();

void getDevices();

// boring getX()/setX() methods cut

private:

vector<Device> _devices;

};


Writer::Writer() {

cout << "Setting up writer object." << endl;

}


void Writer::getDevices() {

map<string, string> deviceInfo = _getDeviceInfo(ID);

Device *drive = new Device( ID, deviceInfo["type"],
atoi(deviceInfo["max_speed"].c_str()));

drive->setInfo( deviceInfo["vendor"], deviceInfo["model"],
deviceInfo["revision"]);

_devices.push_back(drive);

delete drive;

}
}
}


------


gandalf avi:~/doc/IMD2/cdwriter > make
CC -LANG:std Writer.cpp -c -o Writer.o -I. ../vk/ -I/usr/include
cc-1262 CC: ERROR File = /usr/include/CC/stl_construct.h, Line = 53
No instance of constructor "Device::Device" matches the argument list.

new (__p) _T1();
^
A template was detected during header processing.
instantiation of "void std::construct(Device *)" at line 348 of
"/usr/include/CC/stl_vector.h"
instantiation of "void std::vector<Device,
std::allocator<Device>>::push_back()" at line 49 of
"Writer.cpp"

1 error detected in the compilation of "Writer.cpp".
*** Error code 2 (bu21)
 
K

Karl Heinz Buchegger

Avi said:
Hello everybody,

I;m doing my first bits of programming with C++ using the STL. After
falling in love with the map<> container I;m now getting a little
annoyed with its mate vector<>. Using vector with the built-in types
like string and int 'm fine, but I dont understand how to declare/use a
vector filled with my own classes.

I'm obviously not understanding at all how to copy C++ objects.

:)

You need to get more familiar with your compilers error messages
and how to read them

The compiler emits.
gandalf avi:~/doc/IMD2/cdwriter > make
CC -LANG:std Writer.cpp -c -o Writer.o -I. ../vk/ -I/usr/include
cc-1262 CC: ERROR File = /usr/include/CC/stl_construct.h, Line = 53
No instance of constructor "Device::Device" matches the argument list.

new (__p) _T1();
^
A template was detected during header processing.
instantiation of "void std::construct(Device *)" at line 348 of
"/usr/include/CC/stl_vector.h"
instantiation of "void std::vector<Device,
std::allocator<Device>>::push_back()" at line 49 of
"Writer.cpp"

1 error detected in the compilation of "Writer.cpp".
*** Error code 2 (bu21)

So what is this telling?
The compiler is kind enough to emit the source line that gave that
error

new (__p) _T1();

What does it do? It creates a new object. But how does it do that? By
simply plain vanilla creating an object. The compiler will use the
default constructor for that (a default constructor is a constructor
which can be used without supplying arguments).

So lets look at your class:
class Device {

public:

Device(string ID, string Type, int maxSpeed=0);
~Device();

// boring getX()/setX() methods cut

private:

string _ID;
string _type;

};

Hmm. There is no default constructor and since you have declared a constructor
on your own the compiler will not generate one for you. But this constructor
of yours cannot be used, since it requires at least 2 arguments to be passed
and thus does not qualify as a default constructor.

But the compiler needed one for the new from above -> error.
 
A

Andrew Taylor

Avi said:
I'm obviously not understanding at all how to copy C++ objects. If
somebody would be so kind as to explain what I need to do to store my
homebrew classes in a vector container I;d be very grateful.

To store a class in an STL container, it must be assignable. That is,
it must have a copy constructor, and an assignment operator to assign
value from another instance of the same type.

To understand why this is necessary, consider the steps that must happen
when you push_back a Device. The vector ensures it has enough space
allocated for a Device at its back, then copies the Device you provide
into that memory.

You can avoid this by using a vector of Device pointers (or better, a
vector of boost::shared_ptrs), but this is usually not necessary unless
Device is part of a inheritance hierarchy and you are using polymorphism.
 
A

Andrew Taylor

Avi said:
class Writer {
....
private:
vector<Device> _devices;
};

void Writer::getDevices() {
....
Device *drive = new Device( ID, deviceInfo["type"], atoi(deviceInfo["max_speed"].c_str()));
....
_devices.push_back(drive);
....
}

More to the point, you have a vector of Devices, but you are pushing a
pointer to a Device onto the back. Decide whether you want to store the
Devices by value or by pointer (if you store by value, make sure you
have a valid copy ctor and assignment operator as mentioned in my last
post -- this goes for maps, too). Maybe try declaring drive like this:

Device drive( ID, deviceInfo["type"],
atoi(deviceInfo["max_speed"].c_str()));
 
E

Evan Carew

Avi,

Good to see you are experimenting with the STL. Just as an aside, you
might want to add the BOOST library to your STL directory as it has some
great additions to the STL. Comments to your questions follow with the
text of your message:

Avi said:
Hello everybody,

I;m doing my first bits of programming with C++ using the STL. After
falling in love with the map<> container I;m now getting a little
annoyed with its mate vector<>. Using vector with the built-in types
like string and int 'm fine, but I dont understand how to declare/use a
vector filled with my own classes.
In order to use the STL with yser defined objects, and the vector
specifically, your objects need to provide some basic functionality in
order for the STL containers to be able to use them. For example, if you
are simply interested in using your objects with the vector, you need to
support the following functions in your objects:
T(const T&); //public copy constructor
T(); //public default constructor
~T(); //public destructor
T& operator=(const T&); //public assignment operator
In addition, if you want your object to be used in other containers
capable of sorting:
friend bool operator<(const T& lhs, const T& rsh); //public lessthan
friend bool operator==(const T& lhs, const T& rhs); //public equals
operator
I'm obviously not understanding at all how to copy C++ objects. If
somebody would be so kind as to explain what I need to do to store my
homebrew classes in a vector container I;d be very grateful.

grts,

avi
I took the liberty of editing your code to make a working application
from the example you provided. This should give you the necessary
boilerplate code to make your own future objects work with the STL.

#include <map>
#include <string>
#include <vector>

using namespace std;

class Device {
public:
Device(string ID, string Type, int maxSpeed=0);
Device(const Device& device);
// boring /setX() method cut
string getType(){return _type;}
string getID(){return _ID;}
string dumpGuts(){ return getType() + " " + getID();}
Device& operator=(const Device& d){_ID = d._ID; _type = d._type;
return *this;}
friend bool operator<(const Device& lhs, const Device& rhs);
friend bool operator==(const Device& lhs, const Device& rhs);
private:
string _ID;
string _type;
};

typedef map<string, Device> MapType;
typedef MapType::value_type ValuePair;

class Writer {
public:
Writer(){cout << "Setting up writer object." << endl;}
void getDevices();
void addDevice(Device &d);
string _getDeviceInfo(string id);
// boring getX()/setX() methods cut
private:
MapType devices;
};

bool operator<(const Device& lhs, const Device& rhs){
return lhs._type < rhs._type;
}

bool operator==(const Device& lhs, const Device& rhs){
return lhs._type == rhs._type;
}

Device::Device(string ID, string Type, int maxSpeed) {
_ID = ID;
_type = Type;
}

Device::Device(const Device& device) {
_ID = device._ID;
_type = device._type;
}

string Writer::_getDeviceInfo(string id){
Device d = (*devices.find(id)).second;
return d.getType();
}

void Writer::addDevice(Device &d){
devices.insert(ValuePair(d.getID(), d));
}

void Writer::getDevices() {
MapType::iterator iter = devices.begin();
while(iter != devices.end()){
cout << (*iter).second.dumpGuts() << endl;
++iter;
}
}

int main(){
Writer wr;
Device d1("/dev/aux", "Audio"), d2("/dev/random", "Random Numbers"),
d3("/dev/hda", "IDE Hard Drive 1");
wr.addDevice(d1);
wr.addDevice(d2);
wr.addDevice(d3);
wr.getDevices();
return 0;
}
 
E

Evan Carew

Avi,

Good to see you are experimenting with the STL. Just as an aside, you
might want to add the BOOST library to your STL directory as it has some
great additions to the STL. Comments to your questions follow with the
text of your message:

Avi said:
Hello everybody,

I;m doing my first bits of programming with C++ using the STL. After
falling in love with the map<> container I;m now getting a little
annoyed with its mate vector<>. Using vector with the built-in types
like string and int 'm fine, but I dont understand how to declare/use a
vector filled with my own classes.
In order to use the STL with yser defined objects, and the vector
specifically, your objects need to provide some basic functionality in
order for the STL containers to be able to use them. For example, if you
are simply interested in using your objects with the vector, you need to
support the following functions in your objects:
T(const T&); //public copy constructor
T(); //public default constructor
~T(); //public destructor
T& operator=(const T&); //public assignment operator
In addition, if you want your object to be used in other containers
capable of sorting:
friend bool operator<(const T& lhs, const T& rsh); //public lessthan
friend bool operator==(const T& lhs, const T& rhs); //public equals
operator
I'm obviously not understanding at all how to copy C++ objects. If
somebody would be so kind as to explain what I need to do to store my
homebrew classes in a vector container I;d be very grateful.

grts,

avi
I took the liberty of editing your code to make a working application
from the example you provided. This should give you the necessary
boilerplate code to make your own future objects work with the STL.

#include <map>
#include <string>
#include <vector>

using namespace std;

class Device {
public:
Device(string ID, string Type, int maxSpeed=0);
Device(const Device& device);
// boring /setX() method cut
string getType(){return _type;}
string getID(){return _ID;}
string dumpGuts(){ return getType() + " " + getID();}
Device& operator=(const Device& d){_ID = d._ID; _type = d._type;
return *this;}
friend bool operator<(const Device& lhs, const Device& rhs);
friend bool operator==(const Device& lhs, const Device& rhs);
private:
string _ID;
string _type;
};

typedef map<string, Device> MapType;
typedef MapType::value_type ValuePair;

class Writer {
public:
Writer(){cout << "Setting up writer object." << endl;}
void getDevices();
void addDevice(Device &d);
string _getDeviceInfo(string id);
// boring getX()/setX() methods cut
private:
MapType devices;
};

bool operator<(const Device& lhs, const Device& rhs){
return lhs._type < rhs._type;
}

bool operator==(const Device& lhs, const Device& rhs){
return lhs._type == rhs._type;
}

Device::Device(string ID, string Type, int maxSpeed) {
_ID = ID;
_type = Type;
}

Device::Device(const Device& device) {
_ID = device._ID;
_type = device._type;
}

string Writer::_getDeviceInfo(string id){
Device d = (*devices.find(id)).second;
return d.getType();
}

void Writer::addDevice(Device &d){
devices.insert(ValuePair(d.getID(), d));
}

void Writer::getDevices() {
MapType::iterator iter = devices.begin();
while(iter != devices.end()){
cout << (*iter).second.dumpGuts() << endl;
++iter;
}
}

int main(){
Writer wr;
Device d1("/dev/aux", "Audio"), d2("/dev/random", "Random Numbers"),
d3("/dev/hda", "IDE Hard Drive 1");
wr.addDevice(d1);
wr.addDevice(d2);
wr.addDevice(d3);
wr.getDevices();
return 0;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,045
Latest member
DRCM

Latest Threads

Top