In C++, is it possible to reconcile stack-based memory management and polymorphism?
I love declaring variables on the stack, especially when开发者_StackOverflow using the standard container. Each time you avoid a new
, you avoid a potential memory leak.
I also like using polymorphism, ie class hierarchies with virtual functions. However, it seems these features are a bit incompatible: you can't do:
std::vector<BaseType> vec;
vec.push_back(DerivedType())
or at least it seems you would lose the polymorphic nature of the object you push in.
So, is there any way to reconcile stack-based memory management and the use of virtual functions?
Well the obvious answer:
std::vector<BaseType*> vec;
DerivedType d;
vec.push_back(&d);
But probably not what you intended. d
and vec
better die at the same time; if vec
outlives d
you've got a bad pointer.
I think what you really want is something like Boost pointer containers:
boost::ptr_vector<BaseType> vec;
vec.push_back(new DerivedType());
So you don't have to worry about leaks. The pointer containers were made specifically for the task of easing use and storage of polymorphic objects.
In this case you not only lose polymorphic nature, you slice your derived-type object to base type object.
But you can use smart pointers instead.
std::vector<std::tr1::shared_ptr<BaseType> > vec;
vec.push_back(std::tr1::shared_ptr<BaseType>(new DerivedType()));
When you declare std::vector
variable on the stack dynamic memory allocation does happen for the vector's internal array. It's not necessarily from the heap though. The second template parameter of std::vector
defaults to std::allocator
that you can replace with your own custom one.
For managing polymorphic types there are tool like boost::smart_ptr
and boost intrusive library.
You can use a smart pointer implementation either from Boost libraries or the POCO C++ libraries http://www.pocoproject.org.
include "Poco/SharedPtr.h"
include "vector.h"
class Base
{
protected:
std::string somestring;
public:
Base()
{
somestring = "Hello";
}
virtual void Method1() {
std::cout << "Method1 " << somestring.c_str() << std::endl;
}
virtual ~Base()
{
std::cout << "Base" << std::endl;
}
};
class Derived : public Base
{
public:
void Method1()
{
std::cout << "overriden Method1 " << somestring.c_str() << std::endl;
}
~Derived()
{
std::cout << "Derived" << std::endl;
}
};
int main()
{
std::vector<Poco::SharedPtr<Base> > someVector;
for (int i = 0; i < 20 ; i++)
{
Poco::SharedPtr<Base> obj = new Base();
Poco::SharedPtr<Derived> dObj = new Derived();
someVector.push_back(obj);
someVector.push_back(dObj);
}
std::vector<Poco::SharedPtr<Base> >::iterator itr = someVector.begin();
for (int i = 0; i < someVector.size(); i++)
{
someVector[i]->Method1();
}
return 0;
}
If your main interest is in preventing memory leaks, you may wish to look at smart pointers. I would recommend Boost's Smart Pointers .
The conflict is not between polymorphism and (heap or stack) allocation, since standard containers normally allocate their elements on the heap.
The conflict is between polymorphism and (value or reference) semantics. Polymorphism needs the additional level of indirection brought by reference semantics to work, but standard containers have value semantics.
The solution, as already mentioned in the other answers, is to store objects whose values are references to other objects, the simpler of which are pointers.
Smart pointers are best solution as comments suggest.
Another technique -- if you're using polymorphism mostly to hide your class's implementation details -- is Pimpl idiom.
精彩评论