Reputation: 3593
I am using a derived class and a vector of pointers to objects from said class. I'm having some problems implementing copy constructors etc, even after reading a lot about it. I'm using c++11.
I have a loop where new objects of the derived class are created, and I then want to put these into the vector. But since it is a vector of pointers I must put the address of the created object there instead.
I believe my problems stem from this fact, together with objects going out of scope etc and my not being able to implement copy constructors / copy assignment constructors etc in a satisfactory way.
I've made a minimal example that I think illustrates my problem. Let's say the initial setup is as follows (I know it doesn't make much sense, e.g. with the pointer *n
, but I think this shows the issues with my actual code):
using namespace std;
#include <iostream>
#include <vector>
class Base {
protected:
int* n;
public:
void display(string name="") {cout << name << "n = " << *n << endl;}
Base() {}
Base(int n_) {
*n=n_;
cout << "Initialised to " << *n << endl;
}
};
class Derived : public Base {
public:
Derived() : Base() {}
Derived(int n_) : Base(n_) {}
};
int main(int argc, const char* argv[]) {
vector<Base*> list;
for(int i=0;i<5;i++) {
Derived tmp(i);
tmp.display("Tmp: ");
list.push_back(&tmp);
}
cout << endl;
for(int i=0;i<list.size();i++) {
cout << "Address of " << i << ": " << list[i] << endl;
list[i]->display("Element "+to_string(i)+" : ");
}
}
The output of this is:
Initialised to 0
Tmp: n = 0
Initialised to 1
Tmp: n = 1
Initialised to 2
Tmp: n = 2
Initialised to 3
Tmp: n = 3
Initialised to 4
Tmp: n = 4
Address of 0: 0x7fff3a1df2d0
Element 0 : n = 0
Address of 1: 0x7fff3a1df2d0
Element 1 : n = 0
Address of 2: 0x7fff3a1df2d0
Element 2 : n = 0
Address of 3: 0x7fff3a1df2d0
Element 3 : n = 0
Address of 4: 0x7fff3a1df2d0
Element 4 : n = 0
So after the loop all the elements in the list point to the same address, where n=0 (probably undefined behaviour from tmp
going out of scope).
So rather than just putting the address of tmp
into list
I'm thinking I somehow have to make instances of Derived
that survive the loop while still just having addresses in list
.
As mentioned I've tried doing this using various special member functions with no luck.
Note that it might seem implementing a vector of the objects themselves might be easier, but that leads to other problems in my actual code. If I can't get this working I'll try that instead though.
Upvotes: 1
Views: 2667
Reputation: 2822
You add pointers to objects on the stack to your vector. When the current scope ends, these objects will be destroyed, but the pointer is still there.
You'll have to create new objects instead.
int main(int argc, const char* argv[]) {
vector<Base*> list;
for(int i=0;i<5;i++) {
auto tmp = new Derived{i};
tmp->display("Tmp: ");
list.push_back(tmp);
}
// ...
}
}
Now you still have to make sure, you free the objects as needed. Whenever possible prefer to resort to unique_ptr<>
or shared_ptr<>
:
int main(int argc, const char* argv[]) {
vector<unique_ptr<Base>> list;
for(int i=0;i<5;i++) {
auto tmp = make_unique<Derived>(i);
tmp->display("Tmp: ");
// this should move the unique_ptr and therefore transfer
// its ownership to the vector.
list.emplace_back(tmp);
}
// ...
}
}
Now the objects will be destroyed, either when they are removed from the vector, or when the vector is destroyed. With shared_ptr that might be delayed, untill no part of your programm holds any shared_ptr<>
to the same object.
Upvotes: 2
Reputation: 409176
It has nothing to do with with copying or copy-constructors, it is simply only because the objects go out of scope and gets destructed, while you still keep a pointer to these (now destructed) objects. This leads to undefined behavior when you try to dereference these pointers.
Instead you need to dynamically allocate these objects, using e.g. new
. You could wrap these pointers using C++11 smart pointers.
Upvotes: 4