Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 months ago.
Improve this question
The syntax of the destructor is ~classname. This results in the need to explicitly write the type of object in the destructor call. To avoid this, C++17 introduced std::destroy_at.
So, what was Bjarne Stroustrup's original rationale for choosing the ~classname syntax for the destructor? If the syntax does not depend on the types, std::destroy_at is not needed.
First of all, I am not sure about the initial rationale for ~ in ~T(). The thing is that most of the time it does not matter how the destructor is called manually.
Usually you never call a destructor explicitly. Most of your variables should use automatic storage:
{
foo x;
}
The destructor of x is called automatically when x goes out of scope. Explicitly calling the destructor of x is wrong, because once it goes out of scope it would be called again resulting in undefined behavior.
Sometimes you need dynamic allocation (do it via smart pointers, but for the point here manual is "ok"):
foo* p = new foo();
delete p;
You must delete what you created via new. Also here calling the destructor explicitly would be wrong, because delete calls the destructor and frees the allocated memory. Only calling the destructor will not free the memory and calling the destructor twice is undefined behavior.
The only case you have to call a destructor explicitly is when you allocate memory and create the object in two seperate steps via placement new: What uses are there for "placement new"?.
Placement new isn't something you use everyday. It is mainly found in libraries. It is a case where you need to call a destructor explicitly and that is the case when std::destroy_at can be handy.
Suppose you write this code:
void foo() {
auto x = returns_some_pointer();
// ....
... now delete *x ...
}
Suppose returns_some_pointer returns a pointer to some object. Further suppose that object has been created via placement new and at the end of foo we want to call its destructor. foo doesn't need to know the type of x for anything. To call the destructor it would need to know T to be able to call ~T(). The type can be deduced from x itself, but thats not very convenient. A very convenient way to deduce T is to use a function template, and that is destroy_at(x);.
TL;DR: For most cases it does not really matter how the destructor is called, because it will be either called automatically or under the hood by calling delete. std::destroy_at is not a replacement for the destructor, but rather a convenience method to deduce the type of the object whose destructor is to be called.
Constructors and destructors were a part of C++ from the very earliest days. (They predated the name "C++.") They predated templates as well as the standard container types like vector that templates made possible. In those early days there was little or no allowance for manual construction/destruction as a separate operation from new and delete (e.g. there was no placement-new). Nested classes were also not supported.
All in all, there was no question of ever needing to refer to the destructor except as part of its definition, and no question that there would be any doubt or complexity in forming the destructor's identifier.
Naming the constructor after the class fits with C's general tendency for declarations to resemble the usage of the things they declare (e.g. int *a(int b) results in something where *a(b) is well-formed). The destructor is conceptually linked to the constructor, so it would be weird for the class name to show up in the constructor but not the destructor. And with no support for operator overloading (at the time) beyond operator=, there was no question of confusing ~classname with an overloaded operator~. So it was a simple, low-stakes, mildly witty syntax detail.
Related
This question already has answers here:
Will an 'empty' constructor or destructor do the same thing as the generated one?
(7 answers)
Closed 6 years ago.
I'm new to C++, and one of the concepts I'm working on understanding is destructors. Out of curiosity, can an unnecessary (e.g., when a class has no dynamically allocated memory, resources, or anything requiring a user-defined destructor) and empty destructor cause any unforeseen problems?
Edit: I know that part of this has been answered in Will an 'empty' constructor or destructor do the same thing as the generated one? but I wanted to broaden it to ask more about generalized negative consequences such as crashes or making an application slower. There is some overlap, but it is a slightly different question.
The question depends on several parameters. Emptiness isn't the only thing that has effect on the result. E.g., if you don't define virtual destructor (empty or not), you'll get problematic behavior when inheriting from the class. On the other hand, if you define an empty destructor in private or protected section, it will prevent creating instances of the class on stack.
There is also an interesting aspect (which do not seem to be talked about in the linked duplicate) of a triviality of destructor. Compiler-generated (or defaulted) destructors are considered trivial destructors, and having a trivial destructor is a pre-requisite of your class being a POD-type. The user-defined destructor, even if empty, prevents your class from being a POD-type.
And having a POD-type is sometimes very important. For example, POD-types can be memcpyed or entity-serialized.
No, all members of the instance are still destroyed after your destructor ran. The only thing a destructor must not do is throwing an exception, otherwise it may do anything a "proper" method can do, i.e. also doing nothing at all is fine. Not closing handles when you should have is another question.
No. In fact, if you don't declare and write a destructor for a class or struct, the compiler will do it for you - and it will be empty.
"Empty destructor" is a bit of a misnomer. Whether or not your destructor has a body, the compiler will still generate code to call the destructor of every non-static member variable and base class in reverse order of declaration. You only need a body if you wish to do something before those other destructors get called.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
Is it possible to have automatically generated destructors in C++?
It is too big burden to do it by ourselves all the time. Is it so hard
for the compiler to generate destructors? Can't it detect what is a "resource"
and release it in the destructor?
Certainly it is, and that's exactly what the language does. If you don't declare a destructor, then one will be generated for you: it will invoke the destructor of each member and base subobject.
You only need to write your own destructor if you're managing a resource that isn't released automatically; for example, a raw pointer to something that you allocated with new. You shouldn't need such a thing in most classes - use containers, smart pointers and other RAII types to manage these automatically for you.
It can't be detected accurately. Even if the compiler observes that you allocate a resource in the constructor or in some other function of the object, it doesn't necessarily follow that it should be released in the destructor. It all depends whether or not the object "owns" the resource.
Fortunately, C++ does provide a means for you to inform the compiler explicitly what resources the object owns. This means is called "smart pointers", and the types you should read about are shared_ptr and unique_ptr. You can avoid writing destructors by thorough use of smart pointers. The compiler generates a destructor that destroys all your data members, so if the data members are smart pointers then the resources they control are destroyed at the appropriate time.
Is it so hard for the compiler to generate destructors?
It is not a question of what is easy or hard for the compiler to do. It is a question of a fundamental tenet of C++ programming:
You shouldn't have to pay for what you don't need.
This philosophy prevails in every aspect of the design of the language, including how destructors are defined and work.
Every class needs a destructor of some kind. That's why the compiler automatically writes one for you if you don't do it yourself. This implicit destructor destroys all members and base classes in a specific order and in a specific way. Sometimes this isn't what you really want, but that compiler can't assume this. A classic case is with smart pointer classes. A smart pointer class will have a raw pointer to the controlled object somewhere, but the compiler doesn't know if that pointer should be deleted -- maybe you are implementing a reference-counter smart pointer. If you need the destructor to actually delete the pointer, that you have to write yourself.
Another case is with deleteing derived classes. Consider:
Base* p = new Derived;
delete p;
If Derived has a bunch of stuff in it which needs to be released, then you need to make sure that when you delete the Derived object through the Base pointer, Derived's destructor is the one that's actually called -- even though the compiler has no way of knowing at the call site that p actually points to a Derived. In order to make this work, you need to make Base::~Base a virtual destructor.
Neither C++ nor C++11 have garbage collection. C++11 does introduce a number of managed pointer classes in the memory header file--shared_ptr, weak_ptr and unique_ptr. These are designed to help prevent memory leaks. For an explanation see C++ Smart Pointers tutorial and Smart Pointers (Modern C++) on MSDN.
I'm trying to override the + operator for a type whose constructor involves calling new (that is, the constructor needs to dynamically allocate something else) and hence whose destructor involves calling delete. Somewhere, I'd like to be able to use something like:
T c = a + b;
My problem is that I obviously need to create an object of type T inside the + function. If I allocate a temporary instance of T on the stack inside the + function implementation to return by-copy, the destructor to this instance will get called as the + call exits and (or so I believe) before the assignment to c. So that's not an option. My other option seems to be to use new and dereference the pointer returned by new when returning. It seems that the problem with this approach, however, is that the pointer will be inaccessible, and there will be no way to call delete on it.
So my question is...it can't be that overloading operators on types that involve dynamic allocation is that rare. How do people generally handle such a situation?
You make sure T obeys The Rule of 3, and there are no worries.
If you create a temporary object on stack within operator+, then on exit, depending on compiler and your operator implementation:
The object will be passed via copy constructor to another temporary object, which will be passed to c via copy constructor again. OR
The object will be passed to c via copy constructor. OR
The temporary object will be actually c and there will be no copy constructor calls. (see http://en.wikipedia.org/wiki/Return_value_optimization)
As mentioned before, if you follow The Rule of 3 and provide correct implementation of copy constructor and assignment operator there won't be any problems under any circumstances, so you don't need to worry about actual implementation (unless you're crazy about performance). That's all about OOP.
std::string and std::vector are somehow able to do that, and your class is too. I don't suggest you learn their source code, it's quite intimidating. As another poster said, the rule of 3 is your friend. I can add that you should not call new in your function. Allocate on the stack and return by value. C++ will do the necessary magic.
I understand that placement new calls are usually matched with explicit calls to the destructor. My question is: if I have no need for a destructor (no code to put there, and no member variables that have destructors) can I safely skip the explicit destructor call?
Here is my use case: I want to write C++ bindings for a C API. In the C API many objects are accessible only by pointer. Instead of creating a wrapper object that contains a single pointer (which is wasteful and semantically confusing). I want
to use placement new to construct an object at the address of the C object. The C++ object will do nothing in its constructor or destructor, and its methods will do nothing but delegate to the C methods. The C++ object will contain no virtual methods.
I have two parts to this question.
Is there any reason why this idea will not work in practice on any production compiler?
Does this technically violate the C++ language spec?
If I understand your question correctly you have a C object in memory and you want to initialize a C++ object with the same layout "over the top" of the existing object.
CppObject* cppobject = new (cobject) CppObject;
While there is no problem with not calling a destructor for the old object - whether this causes resource leaks or other issues is entirely down to the type of the old object and is a user code issue, not a language conformance issue - the fact that you reuse the memory for a new object means that the old object is no longer accessible.
Although the placement form of operator new must just return the address that it was given, there is nothing to stop the new expression itself wiping the memory for the new object before any constructor (if any) is called. Members of the new object that are not initialized according to C++ language rules have unspecified contents which definitely does not mean the same as having the contents of any old object that once lived in the memory being reused.
If I understand you correctly, what you are trying to do is not guaranteed to work.
I think the answer is that if your class is POD (which it is, if it's true that it does nothing in the con/destructor, has no virtual member functions, and has no non-static data members with any of those things), then you don't need to call a constructor or a destructor, its lifetime is just the lifetime of the underlying memory. You can use it the same way that a struct is used in C, and you can call its member functions regardless of whether it has been constructed.
The purpose of placement new is to allow you to create object pools or align multiple objects together in contiguous memory space as with std::vector.
If the objects are C-structs then you do not need placement new to do this, you can simply use the C method of allocating the memory based on sizeof(struct Foo) where Foo is the struct name, and if you allocate multiple objects you may need to multiple the size up to a boundary for alignment.
However there is no need to placement-new the objects there, you can simply memcpy them in.
To answer your main question, yes you still need to call the destructor because other stuff has to happen.
Is there any reason why this idea will not work in practice on any production compiler?
You had damn well be sure your C++ object fits within the size of the C object.
Does this technically violate the C++ language spec?
No, but not everything that is to spec will work like you want.
I understand that placement new calls are usually matched with explicit calls to the destructor. If I have no need for a destructor (no code to put there, and no member variables that have destructors) can I safely skip the explicit destructor call?
Yes. If I don't need to fly to New York before posting this answer, can I safely skip the trip? :) However, if the destructor is truly unneeded because it does nothing, then what harm is there in calling it?
If the compiler can figure out a destructor should be a no-op, I'd expect it to eliminate that call. If you don't write an explicit dtor, remember that your class still has a dtor, and the interesting case – here – is whether it is what the language calls trivial.
Solution: destroy previously constructed objects before constructing over them, even when you believe the dtor is a no-op.
I want to write C++ bindings for a C API. In the C API many objects are accessible only by pointer. Instead of creating a wrapper object that contains a single pointer (which is wasteful and semantically confusing). I want to use placement new to construct an object at the address of the C object.
This is the purpose of layout-compatible classes and reinterpret_cast. Include a static assert (e.g. Boost's macro, 0x static_assert, etc.) checking size and/or alignment, as you wish, for a short sanity check, but ultimately you have to know a bit of how your implementation lays out the classes. Most provide pragmas (or other implementation-specific mechanisms) to control this, if needed.
The easiest way is to contain the C struct within the C++ type:
// in C header
typedef struct {
int n;
//...
} C_A;
C_A* C_get_a();
// your C++
struct A {
void blah(int n) {
_data.num += n;
}
// convenience functions
static A* from(C_A *p) {
return reinterpret_cast<A*>(p);
}
static A const* from(C_A const *p) {
return reinterpret_cast<A const*>(p);
}
private:
C_A _data; // the only data member
};
void example() {
A *p = A::from(C_get_a());
p->blah(42);
}
I like to keep such conversions encapsulated, rather than strewing reinterpret_casts throughout, and more uniform (i.e. compare call-site for const and non-const), hence the convenience functions. It's also a bit harder to modify the class without noticing this type of use must still be supported.
Depending on the exact class, you might make the data member public.
The first question is: why don't you just use a cast? Then there's no issue of the placement new doing anything, and clearly no issue of failing to use a destructor. The result will work if the C and C++ types are layout compatible.
The second question is: what is the point? If you have no virtual functions, you're not using the constructor or destructor, the C++ class doesn't seem to offer any advantages over just using the C type: any methods you write should have been global functions anyhow.
The only advantage I can imagine is if you want to hide the C representation, you can overlay the C object with a class with all private members and use methods for access. Is that your purpose? [That's a reasonable thing to do I think]
What potential memory leaks won't an implicit destructor handle? I know that if you have anything stored on the heap it won't handle it, and if you have a connection to a file or a database, that needs to be handled manually. Is there anything else? What about, say, non-base data types like vectors?
Also, in an explicit destructor, need you destroy non-heap variables which would have been destroyed by the implicit, or are they handled automatically?
Thanks
vectors and the like will deallocate themselves because their destructor is called.
In fact your problem will lie with anything that would cause a problem of a dangling pointer (or handle or whatever), ie anything that needs to be manually Closed or de-allocated won't be in an implicit destructor. Anything that destructs itself properly will be fine. This is why the RAII idiom is so popular :)
I think the question is upside-down. Don't think in terms of what object destruction doesn't do: think in terms of what it does do.
If a class only has an implicit destructor, then when it is destroyed, all non-static data members are destroyed too, as are all base-class sub-objects.
You can argue a bit whether this is done "by the implicit destructor" or not - if you write a destructor, those things still happen. It's part of the object destruction process itself, rather than part of the code of the destructor as such.
So, if your "connection to a file" is a FILE* class member, then the default destructor doesn't release it, because FILE* is a C thing, and it doesn't have a destructor. Destroying a FILE* does nothing. If your "connection to a file" is a std::ofstream, then it does have a destructor, and the destructor tries to flush and close the connection.
Vector has a destructor which release the vector's resources. This means that in turn the elements in the vector have their destructors called.
For each member variable you have, you should look at the corresponding documentation to see how resources are handled for that type. Obviously with experience, you start to remember the answers.
If the member variable is a pointer, then the implicit destructor doesn't do anything with it. So if it points to heap-allocated memory, and this object holds the only pointer to that memory, then you need to free it to avoid a memory leak.
If you find yourself writing a destructor in C++ that needs to free more than one thing, then you've probably designed the class badly. There are almost certainly exception-safety errors elsewhere in the class: it's possible to get the code right, but if you're experienced enough to get it right then you're experienced enough to make your own life easier by designing it differently ;-). The solution is to write classes with a single responsibility -- to manage a single resource -- and use them as member variables. Or, better, to find library classes that manage the resource you're using. shared_ptr is pretty flexible.
"need you destroy non-heap variables"
There is no such thing in C++ as "heap" and "non-heap" variables. Destroying a pointer does not free the thing pointed to, for the obvious reason that nothing in the type of a pointer tells you how the thing it points to was allocated, or who "owns" it.
You need to understand three things about destructors. Say you have an object t of class T with three members.
class T
{
A a;
B b;
C c;
// ...
} t;
Destructing t ALWAYS means calling the following destructors in that order: ~T(), ~C(), ~B(), ~A(). You cannot influence these semantics. It is impossible to prevent the destruction of the members. This ALWAYS happens, no matter if you define ~T() manually or if the compiler generates it.
Implicitly generated destructors are ALWAYS a no-op. However, as stated in point 1, the destructors ~C(), ~B() and ~A() will still be executed afterwards.
The destructors of scalar types, especially C-style pointers, are ALWAYS a no-op. This is the sole reason why you almost always need to write the destructor (and the copy constructor and the assignment operator) manually when you have a C-style pointer member -- after ~T() has finished, destructing a C-style pointer member does NOTHING, so any cleanup intended on the pointees has to be done in ~T().
I hope this clears things up for you.
What potential memory leaks won't an implicit destructor handle? I know that if you have anything stored on the heap it won't handle it, and if you have a connection to a file or a database, that needs to be handled manually. Is there anything else? What about, say, non-base data types like vectors?
To put it simply, you are correct. The only thing not handled by the implicit destructor is memory allocated in the form of a pointer or another type of resource that needs to be released explicitly.
With regard to vectors or any other class type objects; all classes have a destructor which takes care of releasing their data. The destructor of an object of this type is called when it goes out of scope. All basic data types like: int, float, double, short, bool etc are released in similar fashion.
Also, in an explicit destructor, need you destroy non-heap variables which would have been destroyed by the implicit, or are they handled automatically?
The answer to this is that they are handled automatically, in fact you should never ever try to explicitly call the destructor of an object.
In an implicit destructor the following occurs:
Each of the member variables of the class have their destructors called in turn.
In an explicit destructor the following occurs:
The body of the explicit destructor is executed
Each of the member variables of the class have their destructors called in turn.
So you can see that an explicit destructor is much the same as an implicit one, except that you can take any necessary manual intervention.
Now as a bit of advice with regard to managing memory allocated objects you should pretty much always use RAII (resource acquisition is initialisation). The crux of this is smart pointers, these are pointers that are deleted correctly when they go out of scope just like non heap allocated objects. Ownership becomes an issue once you start using them but that's a story for another day. A good place to start with smart pointers is boost::shared_ptr. (btw if you haven't got on board with boost yet and you write c++ code do yourself a favour...)
The implicit destructor calls the destructor on all member variables.
If you have a raw pointer, its destructor does nothing. So if you own the memory it points to, you have to release it explicitly.
The same applies to any other resource, or any other action you wish to take not implied by the default destructor of the member variable.
The default destructors of members are still called, so vectors, auto_ptrs, files opened using std streams or other C++ libraries all get destroyed. The moral is to wrap any OS objects which need releasing in C++ classes which tidy themselves up, so that application classes don't have to worry about it.
A class' destructor will implicitely call the destructors of all non-static members, then the destructors of virtual base classes, then its own code.
If you have STL containers as class members, you don't have to do anything explicitely--they will free their own memory in their destructors.
You're already making wrong assumptions. If my class holds heap-allocated data using an std::auto_ptr<Data>, the implicit dtor will handle it. No memory will be leaked. The reason is that the implict dtor, like any other dtor, will call the dtors of all members and base classes.
Now, a good class design holds all important resources as members with proper dtors. As a result, the dtor body needs to do nothing to prevent resource leaks. Of course, there is one exception to that rule: resource managing classes themselves manage precisely one resource, and therefore clean up that one resource in their dtor.