I've had some second thoughts on multiple virtual destructors, esp. after reading reading http://blogs.msdn.com/b/oldnewthing/archive/2004/05/07/127826.aspx .
Suppose I have
class Base
{
public:
Base();
virtual ~Base();
private:
Logger* _logger;
};
//and
class Derived : public Base{
public:
Derived();
virtual ~Derived();
private:
Logger* _logger;
};
in the cpp files, in each destructor I am deleting the respective _logger pointers
Base::~Base(){ //base.cpp
delete _logger;
}
Derived::~Derived(){ //derived.cpp
delete _logger;
}
will this work as I intended, without memory leaks?
First off, if you make the base class destructor virtual, all derived classes will automatically get a virtual destructor if you declare them as virtual or not. This is generally true for matching signatures: if a base class has a virtual function with the same signature as a function in a derived class, the function in the derived class is an override and is virtual (although in C++ 2011 you can prevent further overriding using the final keyword in which case another override would create an error).
That said, destructors are special: when you make a destructor virtual it will still be called even if there is another overriding destructor! The only impact of a destructor being virtual is what happens if you delete an object using a pointer to a base class when the object actually happens to be of a derived type: If the destructor isn't virtual you get undefined behavior while the Right Thing happens if the destructor is virtual. For example:
class not_a_base {};
class bad_idea: public not_a_base {};
class a_base { public: virtual ~a_base() {} };
class ok: public a_base {};
int main() {
a_base* ab = new ok;
delete ab; // <---- all is good here!
not_a_base* nab = new bad_idea;
delete nab; // <---- results in undefined behavior
}
The reason destructors are not virtual by default is simply that this would mean that object size is always increased by a word size which is unacceptable in general.
Base::_logger is a different variable then Derived::_logger. So you should delete Derived::_logger in Derived's dctor, or else you leak memory.
Note that this has nothing to with it being private. Consider this example program:
#include <iostream>
class A {
public:
bool foo;
};
class B: public A {
public:
bool foo;
};
int main()
{
B b;
std::cout << &b.B::foo << ' ' << &b.A::foo << '\n';
}
The addresses are different. That means they're different variables, even though they have the same name. This is possible since each class introduces its own namespace, so the names don't really clash. The first is A::foo, the other one B::foo.
Since your destructors are virtual, both will get called, and the correct _logger will be deleted in both of them.
Related
I'm in a situation where in I've to create an object of either type A or B depending on a condition. Both A and B inherit from the same base class, in this case - Base. The base class has a virtual protected destructor.
The variable is declared as std::unique_ptr<Base> member and then depending on the condition, I use either std::make_unique<A> or std::make_unique<B>.
I'm calling member.reset() but getting a compiler error since the destructor is declared protected. But what I don't understand is why is the compiler not able to call the correct destructor since the destructor is also declared virtual.
But is there some other way to fix this? And why exactly does the virtual destructor not help here?
Full code -
#include <iostream>
#include <memory>
using namespace std;
class Base
{
public:
Base() = default;
protected:
virtual ~Base() = default;
private:
int a;
};
class A : public Base
{
};
class B : public Base
{
};
unique_ptr<Base> get_object(bool cond) {
if (cond) {
return make_unique<A>();
} else {
return make_unique<B>();
}
}
int main()
{
cout << "Hello World";
bool cond;
cin >> cond;
unique_ptr<Base> a_or_b = get_object(cond);
a_or_b.reset();
return 0;
}
The base class has a virtual protected destructor.
I don't see any point in that. Making the destructor protected disallows destroying objects through base class pointers. This makes sense as a protection mechanism if doing so would cause undefined behavior (i.e. if the destructor is non-virtual and the most-derived type different from the base class type).
However, making the destructor virtual intents it to be called through the base class pointer in order to destruct also possibly derived class objects, contradicting the effect of protected.
std::unique_ptr is unable to destroy the object through the base class pointer because of the reason given above. virtual does not change that calling the destructor through the base class pointer is disallowed.
See also the C++ core guidelines rule C.35.
Consider the following code snippet:
class A
{
virtual void function();
public:
virtual ~A() {};
}
class B: public A
{
virtual void function() override final;
public:
/*virtual*/ ~B() {}; // does this d-tor have to be declared at all?
}
I can find the info regarding the base class destructor easily, e.g. http://en.cppreference.com/w/cpp/language/destructor
"Deleting an object through pointer to base invokes undefined behavior
unless the destructor in the base class is virtual. A common
guideline is that a destructor for a base class must be either public
and virtual or protected and nonvirtual"
A virtual destructor in a base class is a must, how about the derived class's destructors, do they have to be explicitly declared/defined? I find it quite confusing, since the destructors of the derived classes are automatically virtual too. Is it legal in terms of vtable addressing to skip the derived class's destructor's declaration/definition? What about the following situation:
class A
{
virtual void function();
public:
virtual ~A() {};
}
class B: public A
{
virtual void function() override;
public:
/*virtual*/ ~B() {}; // does this d-tor have to be declared at all?
}
class C: public B
{
virtual void function() override final;
public:
/*virtual*/ ~C() {}; // does this d-tor have to be declared at all?
}
There is no need to define explicitly destructors in derived classes. According to the C++ Standard
If a class has a base class with a virtual destructor, its destructor
(whether user- or implicitly-declared) is virtual
Also if you bother about the access control then
An implicitly declared destructor is an inline public member of its
class.
The compiler will place the address of its implicitly defined destructor in vtable. So vtable for derived classes will store addresses of destructors of derived classes.
For readability of your code you could write for example
class B: public A
{
virtual void function() override final;
public:
virtual ~B() = default;
}
No, it does not need to be declared; classes that inherit from classes with a given function declared to be virtual do not need to declare their inherited form to be virtual for it to be virtual. This includes destructors which are implicitly declared.
As others have stated, no, you don't need to declare a do-nothing destructor in descendent classes because it carries down from the ancestor class.
However, keep in mind that your class C might be derived from some third-party library class B in something like VendorBAwesomeness.dll, and B might in turn be derived from Microsoft's class A in mswonderful.dll.
If you want to be nice to the readers and users of your class, you should consider specifying virtual in your class C because you saw it in the interface for class B when you read about it, and the author of class B did the same when he/she learned about class A.
By passing this information down, you're allowing others to see clearly what your code does without them having to hunt around for the information.
I find The rule of Zero as also mentioned on Peter Sommerlads Slides (p.32) very compelling.
Although, I seem to remember that there was a strict rule that one has to define the destructor virtual, if the class has virtual members and is actually derived.
struct Base {
virtual void drawYourself();
virtual ~Base() {}
};
struct Derived : public Base {
virtual void drawYourself();
};
The body of the destructor may even be empty (it only needs the entry in the vtbl).
I seem to remember that when use the hierarchy
int main() {
Base *obj = new Derived{};
obj->drawYourself(); // virtual call to Derived::drawYourself()
delete obj; // Derived::~Derived() _must_ be called
}
then it is important that delete obj calls the correct destructor. Is it correct, that if I left out the destructor definition totally, it would not become virtual, and therefore the wrong d'tor would be called?
struct Base {
virtual void drawYourself();
// no virtual destructor!
};
This leads me to my final question:
Is the "Rule Of Zero" also true in hierarchies with virtual methods
or do I need to define the virtual destructor in these cases?
Edit: As I was reminded in an answer, my 1sr version of the question had the wrong assumptions. The relevant (virtual) destructor is in Base, not Derived. But my question holds: Do I need to declare (virtual) destructors at all?
It's actually the base destructor that has to be declared virtual, and it's automatically virtual in derived classes:
struct Base {
virtual void drawYourself();
virtual ~Base() = default;
};
struct Derived : public Base {
virtual void drawYourself();
};
But other than that, the rule of zero still holds.
If you do it the way you did it, or if you leave out the virtual destructor, you simply get undefined behavior when deleteing a derived object through a base pointer.
#include<iostream>
class base
{
public:
virtual ~base(){std::cout << "base\n";}
};
class derived : public base
{
private:
~derived(){std::cout << "derived\n";} /* destructor is private */
};
int main()
{
base *pt= new derived;
delete pt;
}
The above program compiles and runs fine.
How does the derived class destructor get invoked being private ?
This will happen not only with destructors.
You can override any virtual public function with a private one.
#include<iostream>
class base
{
public:
virtual void x(){std::cout << "base\n";}
};
class derived : public base
{
private:
void x(){std::cout << "derived\n"; base::x();}
};
int main()
{
base *pt= new derived;
pt->x(); //OK
//((derived *)pt)->x(); //error: ‘virtual void derived::x()’ is private
derived *pt2= new derived;
//pt2->x(); //error: ‘virtual void derived::x()’ is private
((base *)pt2)->x(); //OK
}
Upside/downside of this is you will have to use pointer to base to access this method.
This feature is one of ways to separate public API from customized implementation.
So, in other words, your destructor is getting called because it was declared as public in base and you are calling it trough pointer to base.
That may be surprising, but if you think about it, it's perfectly logical.
What the compiler sees is that you delete a pointer-to-base, which has an accessible destructor. So it has no reason to complain about what you're doing. Incidentially, it's a virtual destructor, but that's not something to complain about either.
At runtime, the virtual destructor is invoked. Since it turns out that the pointer-to-base is really pointing at a derived object, consequently the derived constructor needs to be invoked first.
"But that one is private!" says you. That's right, however, there is no notion of public/private during runtime. So, again, there is no reason for anything bad to happen. No error is generated.
Let's say I have the following code:
class BaseMember
{
};
class DerivedMember : public BaseMember
{
};
class Base
{
private:
BaseMember* mpMember;
protected:
virtual BaseMember* initializeMember(void)
{
return new BaseMember[1];
}
virtual void cleanupMember(BaseMember* pMember)
{
delete[] pMember;
}
public:
Base(void)
: mpMember(NULL)
{
}
virtual ~Base(void)
{
cleanupMember(mpMember);
}
BaseMember* getMember(void)
{
if(!mpMember)
mpMember = initializeMember();
return mpMember;
}
};
class Derived : public Base
{
protected:
virtual BaseMember* initializeMember(void)
{
return new DerivedMember;
}
virtual void cleanupMember(BaseMember* pMember)
{
delete pMember;
}
};
Base and BaseMember are parts of an API and may be subclassed by the user of that API, like it is done via Derived and DerivedMember in the example code.
Base initializes mpBaseMember by a call to it's virtual factory function initializeMember(), so that the derived class can override the factory function to return a DerivedMember instance instead of a BaseMember instance.
However, when calling a virtual function from within a base class constructor, the base implementation and not the derived class override gets called.
Therefor I am waiting with the initialization of mpMember until it gets accessed for the first time (which of course implies, that the base class and any derived class, that may could get derived further itself, are not allowed to access that member from inside the constructor).
Now the problem is: Calling a virtual member function from within the base base destructor will result in a call of the base class implementation of that function, not of the derived class override.
That means that I can't simply call cleanupMember() from within the base class destructor, as that would call it's base class implementation, which may not be able to correctly cleanup the stuff, that the derived implementation of initializeMember() has initialized.
For example the base class and the derived class could use incompatible allocators that may result in undefined behavior when getting mixed (like in the example code - the derived class allocates the member via new, but the base class uses delete[] to deallocate it).
So my question is, how can I solve this problem?
What I came up with is:
a) the user of the API has to explicitly call some cleanup function before the Derived instance gets destructed. That can likely be forgotten.
b) the destructor of the (most) derived class has to call a cleanup function to cleanup stuff which initialization has been triggered by the base class. That feels ugly and not well designed as ownership responsibilities are mixed up: base class triggers allocation, but derived class has to trigger deallocation, which is very counter-intuitive and can't be known by the author of the derived class unless he reads the API documentation thoroughly enough to find that information.
I would really like to do this in a more fail-proof way than relying on the users memory or his reliability to thoroughly read the docs.
Are there any alternative approaches?
Note: As the derived classes may not exist at compile time of the base classes, static polymorphism isn't an option here.
What about a modification of the factory pattern that would include the cleanup method? Meaning, add a attribute like memberFactory, an instance of a class providing creation, cleanup, as well as access to the members. The virtual initialization method would provide and initialize the right factory, the destructor ~Base would call the cleanup method of the factory and destruct it.
(Well, this is quite far from the factory pattern... Perhaps it is known under another name?)
If you really want to do this sort of thing you can do it like this:
class Base {
BaseMember* mpMember;
protected:
Base(BaseMember *m) : mpMember(m) {}
virtual void doCleanupMember(BaseMember *m) { delete [] m; }
void cleanupMember() {
// This gets called by every destructor and we only want
// the first call to do anything. Hopefully this all gets inlined.
if (mpMember) {
doCleanupMember(pmMember);
mpMember = nullptr;
}
}
public:
Base() : mpMember(new BaseMember[1]) { }
virtual ~Base(void) { cleanupMember(); }
};
class Derived : public Base {
virtual void doCleanupMember(BaseMember *m) override { delete m; }
public:
Derived() : Base(new DerivedMember) {}
~Derived() { cleanupMember(); }
};
However there are reasons this is a bad idea.
First is that the member should be owned an exclusively managed by Base. Trying to divide up responsibility for Base's member into the derived classes is complicated and just asking for trouble.
Secondly the ways you're initializing mpMember mean that the member has a different interface depending on who initialized it. Part of the problem you've already run into is that the information on who initialized the member has been destroyed by the type you get to ~Base(). Again, trying to have different interfaces for the same variable is just asking for trouble.
We can at least fix the first problem by using something like shared_ptr which lets up specify a deleter:
class Base {
std::shared_ptr<BaseMember> mpMember;
public:
Base(std::shared_ptr<BaseMember> m) : mpMember(m) { }
Base() : mpMember(std::make_shared<BaseMember>()) { }
virtual ~Base() {}
};
class Derived : virtual public Base {
public:
Derived()
: Base(std::shared_ptr<BaseMember>(new DerivedMember[1],
[](BaseMember *m){delete [] m;} ) {}
};
This only hides the difference in the destruction part of the member's interface. If you had an array of more elements the different users of the member would still have to be able to figure out if mpMember[2] is legal or not.
First of all, you must use RAII idiom when developing in C++. You must free all your resources in destructor, of course if you don't wish to fight with memory leaks.
You can create some cleanupMember() function, but then you should check your resources in destructor and free them if they are not deleted (as cleanupMember can be never called, for example because of an exception). So add destructor to your derived class:
virtual ~Derived()
{
Derived::cleanupMember(mpMember);
}
and manage the member pointer in the class itself.
I also recommend you to use smart pointers here.
Never never never call virtual methods in constructor/destructor because it makes strange results (compiler makes dark and weird things you can't see).
Destructor calling order is child and then parent
You can do like this (but there is probalby a better way) :
private:
// private destructor for prevent of manual "delete"
~Base() {}
public:
// call this instead use a manual "delete"
virtual void deleteMe()
{
cleanupMember(mpMember);
delete this; // commit suicide
}
More infos about suicide :
https://stackoverflow.com/a/3150965/1529139 and http://www.parashift.com/c++-faq-lite/delete-this.html
PS : Why destructor is virtual ?
Let mpMember be protected and let it be initialized in derived class constructor and deallocated in derived destructor.
Inspired by the ideas from https://stackoverflow.com/a/19033431/404734 I have come up with a working solution :-)
class BaseMember
{
};
class DerivedMember : public BaseMember
{
};
class BaseMemberFactory
{
public:
virtual ~BaseMemberFactory(void);
virtual BaseMember* createMember(void)
{
return new BaseMember[1];
}
virtual void destroyMember(BaseMember* pMember)
{
delete[] pMember;
}
};
class DerivedMemberFactory : public BaseMemberFactory
{
virtual BaseMember* createMember(void)
{
return new DerivedMember;
}
virtual void destroyMember(BaseMember* pMember)
{
delete pMember;
}
};
class Base
{
private:
BaseMemberFactory* mpMemberFactory;
BaseMember* mpMember;
protected:
virtual BaseMemberFactory* getMemberFactory(void)
{
static BaseMemberFactory fac;
return &fac;
}
public:
Base(void)
: mpMember(NULL)
{
}
virtual ~Base(void)
{
mpMemberFactory->destroyMember(mpMember);
}
BaseMember* getMember(void)
{
if(!mpMember)
{
mpMemberFactory = getMemberFactory();
mpMember = mpMemberFactory->createMember();
}
return mpMember;
}
};
class Derived : public Base
{
protected:
virtual BaseMemberFactory* getMemberFactory(void)
{
static DerivedMemberFactory fac;
return &fac;
}
};