I have a templated wrapper containing an instance of a class which inherits of a pure virtual class.
My problem is how to store the data inside the wrapper.
- I can't use a copy because pure virtual classes can't be instanciated (or sliced if I use a simple virtual class).
- I didn't managed to keep a reference. This ref becomes invalid because I don't manage the allocation of the object I get (out of scope).
- My only solution is to use pointers, even if I wanted to avoid that because that's not really safe and I need my code to be robust.
What can I do?
Here's a little example that simulate my problem:
#include <iostream>
#include <string>
#include <ctime>
#include <cmath>
using namespace std;
class Module
{
public:
Module() : m(rand())
{
cout << "m = " << m << endl;
}
virtual void f() = 0;
int m;
};
class ModuleA : public Module
{
public:
ModuleA() : ma(rand())
{
cout << "ma = " << ma << endl;
}
void f() {}
int ma;
};
template<typename T>
class Container
{
public:
Container(T e) : element(e) {}
T element;
};
// Objects are created outside of main
ModuleA createModule()
{
return ModuleA();
}
Container<Module&> createContainer()
{
return Container<Module&>(createModule());
}
int main()
{
srand((unsigned int)time(NULL));
Container<Module&> conta = createContainer();
ModuleA& ca1 = dynamic_cast<ModuleA&>(conta.element); // wrong !
system("pause");
return 0;
}
You can use a std::shared_ptr
in your container, i.e.
template<typename T>
class Container
{
public:
// The pointer you get must be managed as well
Container(std::shared_ptr<T> e) : element(e) {}
std::shared_ptr<T> element;
};
and that would be perfectly safe. Indeed if the object goes out of scope in the code that created it, you still have a valid pointer until the container goes itself out of scope. You can tweak a little further the memory ownership relations with std::weak_ptr
or std::unique_ptr
if the semantics of the std::shared_ptr
don't fit exactly your case.
You should definitely look into std::weak_ptr
, as it allows you to forbid some code to take ownership of a pointer, but still permits access if the pointer is valid at the location where you need to access it. It also prevents memory retain cycles because an std::weak_ptr
doesn't own the memory.