I have three classes organized in following manner. Foo is a template class, Bar derived from Foo, and Doo derived from Foo too. All of them implement a doX() member function which is defined in Foo as a virtual function.
I need to have a vector (or any other container) of Bar and Doo objects. For example, a vector of two objects named vec, first element should be a Doo and second should be a Bar. When I call vec[0].doX() Doo::doX() should be called. Defining the vector of pointers to Foo objects, do the job. But I’m not sure where do the instances actually stored. If I put pointers to objects, the allocated memory may be released after leaving the scope that objects are created in.
I prepared a minimal working example for illustrating the problem:
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
class Foo
{
public:
virtual void doX(){cout<<"doX from Foo"<<endl;}
};
template <typename T>
class Bar : public Foo<T>
{
public:
void doX(){cout<<"doX from Bar"<<endl;}
void g(string const &input); // some test function may be used in doX
int x; // some test data may be used in doX
};
template <typename T>
class Doo : public Foo<T>
{
public:
void doX(){cout<<"doX from Doo"<<endl;}
};
void doSomething(vector<Foo<int>* >& target)
{
Foo<int> X;
// do some extreme job to generate X
target.push_back(&X); // ==> This is problematic
}
int main()
{
Foo<int> f;
Bar<int> b;
Doo<int> d;
vector<Foo<int> > v;
v.push_back(f);
v.push_back(b);
v.push_back(d);
v[0].doX(); // doX from Foo
v[1].doX(); // doX from Foo
v[2].doX(); // doX from Foo
vector<Foo<int>*> v2;
v2.push_back(&f); // here is no problem, but if `f` is generated inside
// a function that receives a reference to `vec` there
// will be problems
doSomething(v2); // This is problematic
v2.push_back(&b);
v2.push_back(&d);
v2[0]->doX(); // doX from Foo
v2[1]->doX(); // doX from Foo but dangerous! May crash
v2[2]->doX(); // doX from Bar
v2[3]->doX(); // doX from Doo
return 0;
}
You have correctly identified the problem. You have to make sure that the instances that are pointed to by the pointers in your vector live at least as long as the vector itself. You can store pointers to dynamically allocated objects, which means that you are in charge of controlling their lifetime. This can be achieved by storing pointers to instances created with
new, or better still, smart pointers thereof.In the above example, you have to make sure to delete the elements of the vector when you are done (typically before the vector goes out of scope).
A C++11 example with std::unique_ptrs: