Reputation: 1399
The code is pretty straight forward:
class SuperClass
{
public:
virtual void someMethod() = 0;
};
class SubClass : public SuperClass
{
public:
virtual void someMethod()
{
std::cout << "hello" << std::endl;
}
};
class CallerClass
{
public:
std::vector<SuperClass*> subClasses;
CallerClass()
{
subClasses.push_back(&SubClass());
}
void callMethods()
{
subClasses[0]->someMethod();
}
};
int main(int argx, char**argv)
{
CallerClass cc;
cc.callMethods();
return 0;
}
The problem occurs when I actually call try to call the subClass' 'someMethod()' in the CallerClass' 'callMethods()'. In Visual Studio, it simply breaks at that line of code without any explanation. I have solved the problem by changing push_back(&SubClass()) to push_back(new SubClass()).
I am curious as to why the latter works and not the former. I thought it was because an object created in a method will only exist within the method, and by using 'new', space was actually being allocated for that object after the function ended; but I added an int a = 1 to SuperClass and was able to access it using in a similar fashion to what's inside 'callMethods()'.
I must be missing some fundamental aspect of C++ here. Please inform me. Hopefully it's not something too obvious.
Upvotes: 2
Views: 96
Reputation: 15334
Yes, if you do push_back(&SubClass())
you are adding a pointer to the vector that points to a temporary object. At the end of the expression the temporary object will be deleted. When you call callMethods
you are dereferencing a pointer to a deleted object. This is undefined behaviour, anything could happen, it could even work!
By calling push_back(new SubClass());
you are allocating an object on the heap and adding a pointer to that object to the vector. This object on the heap will not be deleted when the expression ends.
In fact this object will not be deleted at all and would be a memory leak in your program. CallerClass
effectively owns the objects so it is its responsibility to delete them when it is done.
To fix the memory leak there are a couple of changes you need to make. You need to add a public virtual destructor to SuperClass
:
virtual ~SuperClass(){};
This ensures that if you call the destructor on SuperClass
the SubClass
will also be destroyed properly. Then you need to ensure that delete
is called in the CallerClass
destructor. You could do that by explicitly writing a destructor, looping over the elements of the vector and calling delete
but the easier, C++11 way, is to use smart pointers like std::unique_ptr
. If you change your vector to:
std::vector<std::unique_ptr<SuperClass>> subClasses;
then the objects will be automatically deleted in the CallerClass
destructor and you don't have to explicitly write a destructor at all.
Upvotes: 1
Reputation: 9292
In
subClasses.push_back(&SubClass());
You are storing a pointer to a temporary object, which is destroyed just after.
Then, when you call someMethod, you are calling a method on an invalid object pointer which was already deleted.
With
subClasses.push_back(new SubClass());
You are storing a pointer to a valid object, so it works.
Upvotes: 1