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

Discussion in 'C++' started by Avi Bercovich, Jan 13, 2004.

  1. 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)
    Avi Bercovich, Jan 13, 2004
    #1
    1. Advertising

  2. Avi Bercovich wrote:
    >
    > 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.

    --
    Karl Heinz Buchegger
    Karl Heinz Buchegger, Jan 13, 2004
    #2
    1. Advertising

  3. Avi Bercovich wrote:

    >
    > 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.

    --
    Andrew
    Andrew Taylor, Jan 13, 2004
    #3
  4. Avi Bercovich wrote:
    >
    > 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()));

    --
    Andrew
    Andrew Taylor, Jan 13, 2004
    #4
  5. Avi Bercovich

    Evan Carew Guest

    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 Bercovich wrote:
    > 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;
    }
    Evan Carew, Jan 14, 2004
    #5
  6. Avi Bercovich

    Evan Carew Guest

    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 Bercovich wrote:
    > 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;
    }
    Evan Carew, Jan 14, 2004
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ganesh Gella
    Replies:
    5
    Views:
    1,124
    John Harrison
    Jul 14, 2003
  2. Hitesh Bhatiya
    Replies:
    4
    Views:
    4,494
    John Harrison
    Aug 13, 2003
  3. Alex Vinokur
    Replies:
    9
    Views:
    504
    Alex Vinokur
    Apr 11, 2004
  4. Replies:
    8
    Views:
    1,873
    Csaba
    Feb 18, 2006
  5. mlt
    Replies:
    2
    Views:
    1,243
Loading...

Share This Page