简体   繁体   中英

Explicitly deleting destructors and not calling delete

I was reading the C++11 FAQ and noticed this:

 class X4 { ~X4() = delete; // Disallow destruction } 

This implicitly also disallows moving of X4s. Copying is allowed, but deprecated.

I also found this quote .

Deleting the definition of a destructor will require allocation on the free-store because static and automatic objects implicitly invoke the destructor:`

 struct C { ~C()= delete; //prevent automatic and static objects }; 

However, this technique is less useful than it may seem because it prevents delete expressions, too. Singleton objects can use it, though.`

Which makes sense. My question is, is it considered good practice have a Singleton with an explicitly deleted destructor? Also, if anyone knows of any other case scenarios were you shouldn't call delete , please let me know.

Pragmatically, you might sometimes find yourself in a situation where it's unsafe to destroy objects of a particular type. So you'd delete the destructor to prevent anyone trying.

In the case of a Singleton, where there's only ever going to be one instance of the type, failing to destroy it might be less harmful than if there are loads of instances not cleaned up.

One of the problems with Singletons (or any other globally-available object) is that you can lose control of the dependencies on them. Then it's hard to work out a safe order of destruction -- if the global database object logs to the global logger object that you've closed the connection safely, but optionally the global logger object does its logging to the database via the global database object, then you have a problem.

Although you might "solve" this problem by not destroying the global database object, I don't think this should really be called "good practice". It sounds more like a simple way to deal with a bad situation without re-design (although in my example the redesign might be pretty simple too - just make sure that either the DB logger, or the DB itself, does something useful with log messages when the connection is closed. Swallow them, or redirect them to another available destination).

It may be that there are "good" designs in which a particular type of object cannot be destroyed, but it's not the usual way C++ classes are designed.

Also, if anyone knows of any other case scenarios were you shouldn't call delete, please let me know.

Usage of a memory pool is one scenario I can think of.

There is one situation where a destructor will never be called, even for automatic variables: the destructor for an anonymous union inside a class X , when an explicit destructor X::~X is written by the user. Since the union is anonymous, there is simply no way that its destructor can be called by X::~X (it does not now how to call the destructor because it does not know what to call the destructor).

Incidentally, in this situation there is no way for the user to declare the union destructor to be deleted (again for lack of a name), but it can be implicitly deleted.

Curiously in this situation the default destructor X::~X would have called the destructor for the anonymous union. However, whenever allowed this is a purely formal matter and the destructor call has no effect. This is because this is only allowed if all variants of the union have trivial destructors (and therefore the union itself as well); if any of them has a non-trivial destructor, then the destructor of the union is implicitly deleted, making the default destructor of X inoperable (effectively deleted).

However this does not mean that one cannot use a class X containing an anonymous union with at least one member with a non-trivial destructor. It just means that the user-written X::~X must directly destruct the active variant of the anonymous union, bypassing the deleted destructor of the union itself. This is possible, provided the class contains additional members that allow knowing which variant is active. Similarly constructors of X should directly construct at most one variant of the union, bypassing the (possibly deleted) constructor of the anonymous union (unless the variant is POD, such a constructor should not instead directly assign to a variant of the union). In fact the special member functions of an anonymous union are a kind of phantom entities, which cannot be nontrivial, and whose only role is, by possibly being deleted, to effectively propagate that deleted status to the corresponding special member function of the containing X .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM