I know already that some forms of "suicide" are safe (to be considered legal), but, is it specifically safe to perform delete this in a virtual member function?
Note, by "safe", I mean whether the "code" generated by the compiler is able to deal with the construct.
Note, I'm not interested in the pros and cons of doing it, just whether I can consider is safe.
Side question: Does the language standard explicitly or implicitly demand that implementations support any forms of the delete this idiom?
I do not consider this a duplicate of Is delete this allowed?. My question is about whether it is safe to do in a virtual member function.
Here is an outline of what I am pursuing to do
class FooBase {
protected:
virtual void on_idle() { /* no-op by default */ }
};
class Foo : public FooBase {
void on_idle() override final
{
delete this;
}
};
Note that while Foo needs to be heap allocated, other subclasses possibly do not.
Yes, so long as you don't use this afterwards, and neither does anyone else with a pointer to *this, and this was guaranteed to be allocated by new as exactly the type you are deleting it as, or possessing a virtual destructor. (ie, never as a member of another object, in a std::vector, as an automatic storage variable, as a static variable, as a temporary, not new[], not placement new, etc etc etc)
This includes calling non-virtual methods, virtual methods, member access, calling dtors, and a myriad of other things; almost anything other than return; on the next line and somehow every other pointer to *this being cleaned up before you delete this; (or deterministically never being used).
As a general rule, the level of control you have to have over your objects lifetime is so great to make delete this; safe that you can refactor the lifetime management to be external to the class and in a smart resource owner, which maybe maintains its state as a pImpl which it deletes. c++ adores value types, and a type that delete this; can never be treated as a value.
There is nothing in the standard that makes delete this; extra dangerous for virtual objects, other than the higher tendency to inherit.
All types that delete this; should have either a virtual destructor or be final to avoid inheritance issues.
Related
This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 8 years ago.
I read that destructors need to be defined when we have pointer members and when we define a base class, but I am not sure if I completely understand. One of the things I am not sure about is whether or not defining a default constructor is useless or not, since we are always given a default constructor by default. Also, I am not sure if we need to define default constructor to implement the RAII principle (do we just need to put resource allocation in a constructor and not define any destructor?).
class A
{
public:
~Account()
{
delete [] brandname;
delete b;
//do we need to define it?
};
something(){} =0; //virtual function (reason #1: base class)
private:
char *brandname; //c-style string, which is a pointer member (reason #2: has a pointer member)
B* b; //instance of class B, which is a pointer member (reason #2)
vector<B*> vec; //what about this?
}
class B: public A
{
public something()
{
cout << "nothing" << endl;
}
//in all other cases we don't need to define the destructor, nor declare it?
}
The rule of Three and The Rule of Zero
The good ol' way of handling resources was with the Rule of Three (now Rule of Five due to move semantic), but recently another rule is taking over: the Rule of Zero.
The idea, but you should really read the article, is that resource management should be left to other specific classes.
On this regard the standard library provides a nice set of tools like: std::vector, std::string, std::unique_ptr and std::shared_ptr, effectively removing the need for custom destructors, move/copy constructors, move/copy assignment and default constructors.
How to apply it to your code
In your code you have a lot of different resources, and this makes for a great example.
The string
If you notice brandname is effectively a "dynamic string", the standard library not only saves you from C-style string, but automatically manages the memory of the string with std::string.
The dynamically allocated B
The second resource appears to be a dynamically allocated B. If you are dynamically allocating for other reasons other than "I want an optional member" you should definitely use std::unique_ptr that will take care of the resource (deallocating when appropriate) automatically. On the other hand, if you want it to be an optional member you can use std::optional instead.
The collection of Bs
The last resource is just an array of Bs. That is easily managed with an std::vector. The standard library allows you to choose from a variety of different containers for your different needs; Just to mention some of them: std::deque, std::list and std::array.
Conclusion
To add all the suggestions up, you would end up with:
class A {
private:
std::string brandname;
std::unique_ptr<B> b;
std::vector<B> vec;
public:
virtual void something(){} = 0;
};
Which is both safe and readable.
As #nonsensickle points out, the questions is too broad... so I'm gonna try to tackle it with everything I know...
The first reason to re define the destructor would be in The Rule of Three which is on part the item 6 in Scott Meyers Effective C++ but not entirely. The rule of three says that if you re defined the destructor, copy constructor, or copy assignment operations then that means you should rewrite all three of them. The reason is that if you had to rewrite your own version for one, then the compiler defaults will no longer be valid for the rest.
Another example would be the one pointed out by Scott Meyers in Effective C++
When you try to delete a derived class object through a base class pointer and the base class has a non virtual destructor, the results are undefined.
And then he continues
If a class does not contain any virtual functions, that is often an indication that it is not meant to be used as a base class. When a class is not intended to be used as a base class, making the destructor virtual is usually a bad idea.
His conclusion on destructors for virtual is
The bottom line is that gratuitously declaring all destructors virtual is just as wrong as never declaring them virtual. In fact, many people summarize the situation this way: declare a virtual destructor in a class if and only if that class contains at least one virtual function.
And if it is not a Rule Of three case, then maybe you have a pointer member inside your object, and maybe you allocated memory to it inside your object, then, you need to manage that memory in the destructor, this is item 6 on his book
Be sure to check out #Jefffrey's answer on the Rule of Zero
There are precisely two things that necessitate defining a destructor:
When your object gets destructed, you need to perform some action other than destructing all class members.
The vast majority of these actions once was freeing memory, with the RAII principle, these actions have moved into the destructors of the RAII containers, which the compiler takes care of calling. But these actions can be anything, like closing a file, or writing some data to a log, or ... . If you strictly follow the RAII principle, you will write RAII containers for all these other actions, so that only RAII containers have destructors defined.
When you need to destruct objects through a base class pointer.
When you need to do this, you must define the destructor to be virtual within the base class. Otherwise, your derived destructors won't get called, independent of whether they are defined or not, and whether they are virtual or not. Here is an example:
#include <iostream>
class Foo {
public:
~Foo() {
std::cerr << "Foo::~Foo()\n";
};
};
class Bar : public Foo {
public:
~Bar() {
std::cerr << "Bar::~Bar()\n";
};
};
int main() {
Foo* bar = new Bar();
delete bar;
}
This program only prints Foo::~Foo(), the destructor of Bar is not called. There is no warning or error message. Only partially destructed objects, with all the consequences. So make sure you spot this condition yourself when it arises (or make a point to add virtual ~Foo() = default; to each and every nonderived class you define.
If none of these two conditions are met, you don't need to define a destructor, the default constructor will suffice.
Now to your example code:
When your member is a pointer to something (either as a pointer or a reference), the compiler does not know ...
... whether there are other pointers to this object.
... whether the pointer points to one object, or to an array.
Hence, the compiler can't deduce whether, or how to destruct whatever the pointer points to. So the default destructor never destructs anything behind a pointer.
This applies both to brandname and to b. Consequently, you need a destructor, because you need to do the deallocation yourself. Alternatively, you can use RAII containers for them (std::string, and a smart pointer variant).
This reasoning does not apply to vec because this variable directly includes a std::vector<> within the objects. Consequently, the compiler knows that vec must be destructed, which in turn will destruct all its elements (it's a RAII container, after all).
If you dynamically allocate memory, and you want this memory to be deallocated only when the object itself is "terminated", then you need to have a destructor.
The object can be "terminated" in two ways:
If it was statically allocated, then it is "terminated" implicitly (by the compiler).
If it was dynamically allocated, then it is "terminated" explicitly (by calling delete).
When "terminated" explicitly using a pointer of a base-class type, the destructor has to be virtual.
We know that if a destructor is not provided, the compiler will generate one.
This means that anything beyond simple cleanup, such as primitive types, will require a destructor.
In many cases, dynamic allocation or resource acquisition during construction, has a clean up phase. For example, dynamically allocated memory may need to be deleted.
If the class represents a hardware element, the element may need to be turned off, or placed into a safe state.
Containers may need to delete all of their elements.
In summary, if the class acquires resources or requires specialized cleanup (let's say in a determined order), there should be destructor.
I'm learning C++ while I run into this situation, where I want to implement an equivalently efficient version in C++ of the following symbolic code in C.
<header.h>
struct Obj;
Obj* create(...);
void do_some_thing(Obj*);
void do_another_thing(Obj*);
void destroy(Obj*);
The requirements are:
The implementation is provided in a library (static/dynamic) and the
header doesn't expose any detail other than the interface
It should be equally efficient
Exposing an interface (COM-like) with virtual functions doesn't qualify; that's a solution to enable polymorphism (more than one implementation exposed through the same interface) which isn't the case, and since I don't need the value it brings, I can't see why I should pay the cost of calling functions through 2 indirect pointers.
So my next thought was the pimpl idiom:
<header.h>
class Obj {
public:
Obj();
~Obj();
void do_some_thing();
void do_another_thing();
private:
class Impl;
smart_ptr<Impl> impl_; // ! What should I use here, unique_ptr<> or shared_ptr<> ?
};
shared_ptr<> doesn't seem to qualify, I would pay for unnecessary interlocked increment/decrement that didn't exist in the original implementation.
On the other hand unique_ptr<> makes Obj non-copyable. This means that the client can't call his own functions that take Obj by value, and Obj is merely a wrapper for a pointer, so essentially he can't pass pointers by value! He could do that in the original version. (passing by reference still doesn't qualify: he's still passing a pointer to a pointer)
So what should be the equally efficient way to implement this in C++?
EDIT:
I gave it some more thought and I came to this solution:
<header.h>
class ObjRef // I exist only to provide an interface to implementation
{ // (without virtual functions and their double-level indirect pointers)
public:
ObjRef();
ObjRef(ObjRef); // I simply copy pointers value
ObjRef operator=(ObjRef); // ...
void do_some_thing();
void do_another_thing();
protected:
class Impl;
Impl* impl_; // raw pointer here, I'm not responsible for lifetime management
};
class Obj : public ObjRef
{
Obj(Obj const&); // I'm not copyable
Obj& operator=(Obj const&); // or assignable
public:
Obj(Obj&&); // but I'm movable (I'll have to implement unique_ptr<> functionality)
Obj& operator=(Obj&&);
Obj();
~Obj(); // I destroy impl_
// and expose the interface of ObjRef through inheritance
};
Now I return to client Obj, and If client needs to distribute the usage of Obj by calling some other his functions, he can declare them as
void use_obj(ObjRef o);
// and call them:
Obj o = call_my_lib_factory();
use_obj(o);
Why not keep the C original? The reason that you didn't have to pay the reference counting premium in the C version is that the C version relied on the caller to keep any tally of the number of copies of Obj* in use.
By trying to ensure that the replacement is both copyable and that ensure that the underlying destroy method is only called once the last reference is destroyed you are imposing additional requirements over the original, so it is only natural that the proper solution (which seems to me to be shared_ptr) has some limited additional expense over the original.
I assume there's a reason why you need the a pointer to the object in the first place. Because the simplest, and most efficient approach, would be to just create it on the stack:
{
Obj x(...);
x.do_some_thing();
x.do_another_thing();
} // let the destructor handle `destroy()` when the object goes out of scope
But say you need it created on the heap, for whatever reason, most of it is just as simple, and just as efficient:
{
std::unique_ptr<Obj> x = Obj::create(...); // if you want a separate `create` function
std::unique_ptr<Obj> x = new Obj(...); // Otherwise, a plain constructor will do
x->do_some_thing();
x->do_another_thing();
} // as before, let the destructor handle destruction
There is no need for inheritance or interfaces or virtual functions. You're writing C++, not Java. One of the fundamental rules of C++ is "don't pay for what you don't use". C++ is as performant as C by default. You don't have to do anything special to achieve good performance. All you have to do is not use the features which have a performance cost if you don't need them.
You didn't need reference counting in your C version, so why would you use reference counting in the C++ version (with shared_ptr)? You didn't need the functionality that virtual functions provide in the C version (where it would be implemented through function pointers), so why would you make anything virtual in the C++ function?
But C++ lets you tidy up the create/destroy stuff in particular, and that costs you nothing. So use that. Create the object in its constructor, and let its destructor destroy it. And just place the object in an appropriate scope, so it'll go out of scope when you want it destroyed. And it gives you nicer syntax for calling "member" functions, so make use of that too.
On the other hand unique_ptr<> makes Obj non-copyable. This means that the client can't call his own functions that take Obj by value, and Obj is merely a wrapper for a pointer, so essentially he can't pass pointers by value! He could do that in the original version. (passing by reference still doesn't qualify: he's still passing a pointer to a pointer)
The client can take Obj by value if you use move semantics. But if you want the object to be copied, then let it be copied. Use my first example, and create the object on the stack, and just pass it by value when it needs to be passed by value. It it contains any complex resources (such as pointers to allocated memory), then be sure to write an appropriate copy constructor and assignment operator, and then you can create the object (on the stack, or wherever you need it), pass it around as you desire, by value, by reference, by wrapping it in a smart pointer, or by moving it (if you implement the necessary move constructor and move assignment operator).
Here's a problem scenario: I've got a C++ object that includes a Cleanup() virtual method that needs to be called just before the object is destroyed. In order to do the right thing, this Cleanup method needs access to the fully-formed object (including subclass data), so I can't just call Cleanup() at the start of my own class's destructor, because by the time my class's destructor is called, the destructors any subclasses have already completed and they may have already freed some data that Cleanup() needed to look at.
The obvious solution would be to require the calling code to manually call my routine before deleting the object:
theObject->Cleanup();
delete theObject;
but that solution is fragile, since sooner or later somebody (probably me) will forget to call Cleanup() and bad things will happen.
Another solution would be to have a "holder" object that implements the pImpl technique to wrap the class, and have the holder object's destructor call Cleanup() on the object before deleting the object; but that solution isn't 100% desirable either, since it makes the class work differently from a standard C++ class and makes it impossible to allocate the object on the stack or statically.
So the question is, is there some clever technique (either in C++ or C++11) that I could use to tell the compiler to automatically call a specified (presumably virtual) method on my object before it calls the first subclass-destructor?
(come to think of it, a similar mechanism for automatically calling an Init() method -- just after the last subclass-constructor completes -- might be handy as well)
Lateral thinking: get rid of the Cleanup method, that's what a virtual destructor is for.
The very goal of a virtual destructor is to allow the outmost derived class destructor to be called when delete basepointer; is executed; and as RAII demonstrated, cleanup is the destructor's job.
Now you might argue that you would like an early Cleanup method, to ease the task of the destructor or maybe to reuse the object (kinda like a Reset method in a way). In practice, it rapidly turns into a maintenance nightmare (too easy to forget to clean one field and have state leak from one use to another).
So ask yourself the question: Why not use the destructor for what it's been created for ?
You can use a twist on the PIMPL wrapper:
class PIMPL
{
MyDataThatNeedsInitDestroy object;
public:
PIMPL(Atgs a)
: object(a)
{
object.postCreationInit();
}
~PIMP()
{
object.preDestructionDestory();
}
// All other methods are available via -> operator
MyDataThatNeedsInitDestroy* operator->() { return &object);
};
Yes, this can be done with virtual inheritance, because virtual base subobjects are always constructed (and destroyed) by the most-derived type, and the order of construction (and destruction) of base classes is well-defined also.
Of course, you also may make the delete operator private, and provide a Release() member function consisting of Cleanup(); delete this; But that wouldn't help with stack-allocated objects.
struct B
{
void cleanup()
{
if (!m_bCleanedUp)
{
m_bCleanedUp = true;
...
}
}
virtual B::~B()
{
assert(m_bCleanedUp);
...
}
bool m_bCleanedUp = false;
};
struct D : B
{
D::~D()
{
cleanup(); // if D author forgets, assert will fire
...
}
};
Is there a way to get a C++ class to automatically execute a method just before it starts executing the destructor?
You need to use smart pointer (shared_ptr - available in boost or c++11) with custom deleter instead of raw pointers.
typedef shared_ptr<MyClass> MyClassPtr;
class MyClassDeleter{
public:
void operator()(MyClass* p) const{
if (p)
p->cleanup();
delete p;
}
};
...
MyClassPtr ptr(new MyClass, MyClassDeleter());
--EDIT--
This will work for dynamically allocated objects. There is no solution (I can think of) for stack-allocated objects, so the reasonable action would be to make constructors private and make friend factory method that returns shared_ptr to constructed object - assuming you really need this mechanism.
I want to return an implementation of a class from a function. The function is in a library. I want to prevent the user from destroying the objects I return. How can I achieve this?
EDIT: Example.
Interface to the world:
class Base
{
public:
virtual void foo() = 0;
};
Base* GetFoo();
Implementation - Internal:
class Bar : public Base
{
public:
void foo() { //Do something}
};
Base* GetFoo()
{
return new Bar
}
You could use a private destructor and create some method (release()) to allow the object to be freed in a controlled manner.
Private destructors
What is the use of having destructor as private?
And to answer your question as you are deriving from base, so you cannot make base destructor private. You can achieve your goal by protected destructor.
Return a shared_ptr<Base> and keep a copy of the pointer yourself. That pointer will keep the object alive, no matter what the user will do with his shared_ptr<Base>. You might even consider returning a weak_ptr<Base> instead, to stress that the lifetime of the object is subject to your whims only.
Why would you want to do that? The user should be getting a copy of the returned object anyway, and it should be up to them whether to allocate or deallocate the copy.
You cannot prohibit the user of your library to shoot himself in a leg while cleaning a loaded gun. I.e. even if you return a constant reference, one could take address from it and then delete it. So you should make your code stable even in this situation.
P.S. private destructors (#nc3b) impose limitations on a further usage of the class (no more local non-dynamic instances, for example), so consider them wisely.
If what you're returning is a new object, then there is no reason why you should need to prevent the user from delete ing it.
However, you shouldn't leave any question about responsibility for deletion. Instead, either use a smart pointer to return the value, or use the polymorphic pImpl pattern (wherein a non-polymorphic wrapper contains a smart pointer to a polymorphic implementation - typically a smart pointer that provides value semantics, such as this ) instead of just returning a derived instance.
I have objects which create other child objects within their constructors, passing 'this' so the child can save a pointer back to its parent. I use boost::shared_ptr extensively in my programming as a safer alternative to std::auto_ptr or raw pointers. So the child would have code such as shared_ptr<Parent>, and boost provides the shared_from_this() method which the parent can give to the child.
My problem is that shared_from_this() cannot be used in a constructor, which isn't really a crime because 'this' should not be used in a constructor anyways unless you know what you're doing and don't mind the limitations.
Google's C++ Style Guide states that constructors should merely set member variables to their initial values. Any complex initialization should go in an explicit Init() method. This solves the 'this-in-constructor' problem as well as a few others as well.
What bothers me is that people using your code now must remember to call Init() every time they construct one of your objects. The only way I can think of to enforce this is by having an assertion that Init() has already been called at the top of every member function, but this is tedious to write and cumbersome to execute.
Are there any idioms out there that solve this problem at any step along the way?
Use a factory method to 2-phase construct & initialize your class, and then make the ctor & Init() function private. Then there's no way to create your object incorrectly. Just remember to keep the destructor public and to use a smart pointer:
#include <memory>
class BigObject
{
public:
static std::tr1::shared_ptr<BigObject> Create(int someParam)
{
std::tr1::shared_ptr<BigObject> ret(new BigObject(someParam));
ret->Init();
return ret;
}
private:
bool Init()
{
// do something to init
return true;
}
BigObject(int para)
{
}
BigObject() {}
};
int main()
{
std::tr1::shared_ptr<BigObject> obj = BigObject::Create(42);
return 0;
}
EDIT:
If you want to object to live on the stack, you can use a variant of the above pattern. As written this will create a temporary and use the copy ctor:
#include <memory>
class StackObject
{
public:
StackObject(const StackObject& rhs)
: n_(rhs.n_)
{
}
static StackObject Create(int val)
{
StackObject ret(val);
ret.Init();
return ret;
}
private:
int n_;
StackObject(int n = 0) : n_(n) {};
bool Init() { return true; }
};
int main()
{
StackObject sObj = StackObject::Create(42);
return 0;
}
Google's C++ programming guidelines have been criticized here and elsewhere again and again. And rightly so.
I use two-phase initialization only ever if it's hidden behind a wrapping class. If manually calling initialization functions would work, we'd still be programming in C and C++ with its constructors would never have been invented.
Depending on the situation, this may be a case where shared pointers don't add anything. They should be used anytime lifetime management is an issue. If the child objects lifetime is guaranteed to be shorter than that of the parent, I don't see a problem with using raw pointers. For instance, if the parent creates and deletes the child objects (and no one else does), there is no question over who should delete the child objects.
KeithB has a really good point that I would like to extend (in a sense that is not related to the question, but that will not fit in a comment):
In the specific case of the relation of an object with its subobjects the lifetimes are guaranteed: the parent object will always outlive the child object. In this case the child (member) object does not share the ownership of the parent (containing) object, and a shared_ptr should not be used. It should not be used for semantic reasons (no shared ownership at all) nor for practical reasons: you can introduce all sorts of problems: memory leaks and incorrect deletions.
To ease discussion I will use P to refer to the parent object and C to refer to the child or contained object.
If P lifetime is externally handled with a shared_ptr, then adding another shared_ptr in C to refer to P will have the effect of creating a cycle. Once you have a cycle in memory managed by reference counting you most probably have a memory leak: when the last external shared_ptr that refers to P goes out of scope, the pointer in C is still alive, so the reference count for P does not reach 0 and the object is not released, even if it is no longer accessible.
If P is handled by a different pointer then when the pointer gets deleted it will call the P destructor, that will cascade into calling the C destructor. The reference count for P in the shared_ptr that C has will reach 0 and it will trigger a double deletion.
If P has automatic storage duration, when it's destructor gets called (the object goes out of scope or the containing object destructor is called) then the shared_ptr will trigger the deletion of a block of memory that was not new-ed.
The common solution is breaking cycles with weak_ptrs, so that the child object would not keep a shared_ptr to the parent, but rather a weak_ptr. At this stage the problem is the same: to create a weak_ptr the object must already be managed by a shared_ptr, which during construction cannot happen.
Consider using either a raw pointer (handling ownership of a resource through a pointer is unsafe, but here ownership is handled externally so that is not an issue) or even a reference (which also is telling other programmers that you trust the referred object P to outlive the referring object C)
A object that requires complex construction sounds like a job for a factory.
Define an interface or an abstract class, one that cannot be constructed, plus a free-function that, possibly with parameters, returns a pointer to the interface, but behinds the scenes takes care of the complexity.
You have to think of design in terms of what the end user of your class has to do.
Do you really need to use the shared_ptr in this case? Can the child just have a pointer? After all, it's the child object, so it's owned by the parent, so couldn't it just have a normal pointer to it's parent?