Suppose I have the following classes and objects:
#include <iostream>
class Animal
{
public:
virtual void makeNoise() = 0;
void eat()
{
std::cout << "Eating..." << "\n";
}
void sleep()
{
std::cout << "Sleeping..." << "\n";
}
};
class Cat: public Animal
{
public:
void makeNoise()
{
std::cout << "Miow..." << "\n";
}
};
class Cow: public Animal
{
public:
void makeNoise()
{
std::cout << "Mooo..." << "\n";
}
};
int main()
{
Animal *animal;
Cat *cat = new Cat();
Cow *cow = new Cow();
animal = cat;
animal->eat();
animal->sleep();
animal->makeNoise();
animal = cow;
animal->eat();
animal->sleep();
animal->makeNoise();
return 0;
}
Note that animal is an abstract class.
How can I properly delete the pointers animal
, cat
and cow
?
When I try to delete animal;
I get the following warning message:
warning: deleting object of abstract class type 'Animal' which has non-virtual destructor will cause undefined behaviour.
In the other hand, when I try to delete cat;
I get the following message:
warning: deleting object of polymorphic class type 'Cat' which has non-virtual destructor might cause undefined behaviour.
You can't create an object of an abstract class type. However, you can use pointers and references to abstract class types.
You can create an abstract base class with only a virtual destructor.
No. The only exception to that would be if deltaTime was created with new and it was the responsibility of Update to return the memory (unlikely, and a poor design). like you would with any other pointer? Just because something is a pointer does not mean you should call delete .
Default destructors call destructors of member objects, but do NOT delete pointers to objects. Thus, we need to write destructors that explicitly call delete.
Then we end up with a memory leak: the vector no longer contains the pointers to 2, but no one has called delete on them. So we may be tempted to separate std::remove_if from the call to erase in order to delete the pointers at the end of the vector between the calls: But this doesn’t work either, because this creates dangling pointers.
Makes type from pointer to type. The type to modify. An instance of remove_pointer<T> holds a modified-type that is T1 when T is of the form T1*, T1* const, T1* volatile, or T1* const volatile, otherwise T.
A string literal exists for the whole duration of the program and can't be deleted. What you might want to do in your constructor is to create a copy of the string. Otherwise you will have problems if the string that is passed to the constructor is not a string literal because it could be destroyed before the class object is destroyed.
warning: deleting object of polymorphic class type 'Cat' which has non-virtual destructor might cause undefined behaviour. c++ Share Improve this question Follow asked Dec 7, 2017 at 19:53
A basic C++ rule says that destructors work their way up from the derived class to the base class. When a Cat
is destroyed, then the Cat
part is destroyed first and the Animal
part is destroyed after.
delete animal;
is undefined behaviour because in order to properly follow C++ destruction rules, one must know, at runtime, which derived class part should be destroyed before the Animal
base part. A virtual
destructor does exactly that - it enables a dynamic dispatch mechanism that makes sure destruction works as designed.
You have no virtual
destructor, however, so delete animal
just doesn't make sense. There is no way to call the correct derived-class destructor, and destroying only the Animal
part wouldn't exactly be meaningful behaviour, either.
Therefore, the C++ language makes no assumptions about what will happen in such a situation.
Your compiler is nice enough to warn you about this.
With delete cat
, the situation is slightly different. The static type of the cat
pointer is Cat*
, not Animal*
, so it is clear even without any dynamic dispatch mechanism which derived-class destructor to call first.
The compiler still warns you about this, but it does so with a different wording ("might cause" vs. "will cause"). I believe the reason is that Cat
might itself be the base class for more derived classes, seeing as it is already part of a class hierarchy with virtual
functions.
It apparently doesn't bother to execute a more complete code analysis to find out that delete cat
is really harmless.
In order to fix this, make the Animal
destructor virtual
. While you're at it, replace your raw pointers with std::unique_ptr
. You still have to follow the virtual
destructor rule for classes like yours, but you no longer have to perform a manual delete
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With