In my opinion, the following code (from some C++ question) should lead to UB, but the it seems it is not. Here is the code:
#include <iostream>
using namespace std;
class some{ public: ~some() { cout<<"some's destructor"<<endl; } };
int main() { some s; s.~some(); }
and the answer is:
some's destructor
some's destructor
I learned form c++ faq lite that we should not explicitly call destructor. I think after the explicitly call to the destructor, the object s should be deleted. The program automatically calls the destructor again when it's finished, it should be UB. However, I tried it on g++, and get the same result as the above answer.
Is it because the class is too simple (no new/delete involved)? Or it's not UB at all in this case?
The behavior is undefined because the destructor is invoked twice for the same object:
Once when you invoke it explicitly
Once when the scope ends and the automatic variable is destroyed
Invoking the destructor on an object whose lifetime has ended results in undefined behavior per C++03 §12.4/6:
the behavior is undefined if the destructor is invoked for an object whose lifetime has ended
An object's lifetime ends when its destructor is called per §3.8/1:
The lifetime of an object of type T ends when:
— if T is a class type with a non-trivial destructor (12.4), the destructor call starts, or
— the storage which the object occupies is reused or released.
Note that this means if your class has a trivial destructor, the behavior is well-defined because the lifetime of an object of such a type does not end until its storage is released, which for automatic variables does not happen until the end of the function. Of course, I don't know why you would explicitly invoke the destructor if it is trivial.
What is a trivial destructor? §12.4/3 says:
A destructor is trivial if it is an implicitly-declared destructor and if:
— all of the direct base classes of its class have trivial destructors and
— for all of the non-static data members of its class that are of class type (or array thereof), each such class has a trivial destructor.
As others have mentioned, one possible result of undefined behavior is your program appearing to continue running correctly; another possible result is your program crashing. Anything can happen and there are no guarantees whatsoever.
It's undefined behavior -- but as with any UB, one possibility is that it (more or less) appears to work, at least for some definition of work.
Essentially the only time you need (or want) to explicitly invoke a destructor is in conjunction with placement new (i.e., you use placement new to create an object at a specified location, and an explicit dtor invocation to destroy that object).
From http://www.devx.com/tips/Tip/12684
Undefined behavior indicates that an implementation may behave unpredictably when a program reaches a certain state, which almost without exception is a result of a bug. Undefined behavior can be manifested as a run time crash, unstable and unreliable program state, or--in rare cases--it may even pass unnoticed.
In your case it doesn't crash because the destructor doesn't manipulate any field; actually, your class doesn't have any data members at all. If it did and in destructor's body you manipulated it in any way, you would likely get a run-time exception while calling destructor for the second time.
The problem here is that deletion / deallocation and destructors are separate and independent constructs. Much like new / allocation and constructors. It is possible to do only one of the above without the other.
In the general case this scenario does lack usefulness and just lead to confusion with stack allocated values. Off the top of my head I can't think of a good scenario where you would want to do this (although I'm sure there is potentially one). However it is possible to think of contrived scenarios where this would be legal.
class StackPointer<T> {
T* m_pData;
public:
StackPointer(T* pData) :m_pData(pData) {}
~StackPointer() {
delete m_pData;
m_pData = NULL;
}
StackPointer& operator=(T* pOther) {
this->~StackPointer();
m_pData = pOther;
return this;
}
};
Note: Please don't ever code a class this way. Have an explicit Release method instead.
It most likely works fine because the destructor does not reference any class member variables. If you tried to delete a variable within the destructor you would probably run into trouble when it is automatically called the second time.
Then again, with undefined behavior, who knows? :)
What the main function does is reserving space on the stack, calling some's constructor, and at the end calling some's destructor. This always happens with a local variable, whatever code you put inside the function.
Your compiler won't detect that you manually called the destructor.
Anyway you should never manually call an object's destructor, except for objects created with placement-new.
I believe that if you want your code to be OK you simply need to call placement new and fill it back in before exiting. The call to the destructor isn't the issue, it's the second call to the destructor made when you leave scope.
Can you define the undefined behaviour you expect? Undefined doesn't mean random (or catastrophic): the behaviour of a given program may be repeatable between invocations, it just means you can't RELY on any particular behaviour because it is undefined and there is no guarantee of what will happen.
It is undefined behaviour. The undefined behaviour is the double destructor call and not with the destructor call itself. If you modify your example to:
#include <iostream>
using namespace std;
class some{ public: ~some() { [INSERT ANY CODE HERE] } };
int main() { some s; s.~some(); }
where [INSERT ANY CODE HERE] can be replaced with any arbitrary code. The results have unpredictable side effects, which is why it is considered undefined.
Related
If we are implementing, for example, smart pointers, and we want to do a = std::move(b) --- we need to delete memory to which a is pointing, but can we call destructor inside move assignment operator, instead of copy-pasting destructor's function body?
Is the behavior on calling destructor inside move-assignment defined?
If it's not, are there any better ways dealing with it rather than copy-pasting destructor's body?
You are allowed to call the destructor on this inside a member function and it has well-defined behavior.
However, that behavior involves ending the lifetime of the object *this. After the destructor call you are not allowed to access/use any members of the object anymore. This also has bad consequences in many situations, e.g. if the object has automatic storage duration the destructor will be called a second time on it during scope exit, which would cause undefined behavior.
So that isn't useful for what you want to do.
Although I strongly advice against it, in theory you could then follow the destructor call by construction of a new object at the same storage location via placement-new. However there are some preconditions outside the control of the class on when this is allowed without causing undefined behavior down the line. Under some conditions such a placement-new itself might be undefined behavior, under some conditions the names/references/pointers referring to the old object will not refer to the new one causing undefined behavior if used after the placement-new and under some conditions the lifetime of any parent object that *this is a subobject/member of will also be ended by such an operation, causing undefined behavior if used afterwards.
You can see a demonstration on how this would be implemented, against my advice and under certain (unstated) assumptions, in the standard (draft): https://timsong-cpp.github.io/cppwp/n4868/basic.life#example-2
The linked example and the paragraph preceding it don't spell out all the conditions and possible problems with the approach that I hinted at above. Only the very specific usage of the class/function shown in the example is definitively allowed.
If you just want to reuse code, move the body of the destructor into a new member function and call that one from both locations requiring the same behavior.
Explictly calling destuctor is technically available, you can use this->~Object() in non static method of the class Object.
However this is a bad practice. Consider use these instead.
class Test {
public:
Test() {}
~Test() {
Deallocate();
}
Test(const Test& other) = delete;
Test(Test&& other) {
Deallocate();
// Do sth
}
private:
void Deallocate() {
// Do sth
}
};
I stumbled upon the following code snippet:
#include <iostream>
#include <string>
using namespace std;
class First
{
string *s;
public:
First() { s = new string("Text");}
~First() { delete s;}
void Print(){ cout<<*s;}
};
int main()
{
First FirstObject;
FirstObject.Print();
FirstObject.~First();
}
The text said that this snippet should cause a runtime error. Now, I wasn't really sure about that, so I tried to compile and run it. It worked. The weird thing is, despite the simplicity of the data involved, the program stuttered after printing "Text" and only after one second it completed.
I added a string to be printed to the destructor as I was unsure if it was legal to explicitly call a destructor like that. The program printed twice the string. So my guess was that the destructor is called twice as the normal program termination is unaware of the explicit call and tries to destroy the object again.
A simple search confirmed that explicitly calling a destructor on an automated object is dangerous, as the second call (when the object goes out of scope) has undefined behaviour. So I was lucky with my compiler (VS 2017) or this specific program.
Is the text simply wrong about the runtime error? Or is it really common to have runtime error? Or maybe my compiler implemented some kind of warding mechanism against this kind of things?
A simple search confirmed that explicitly calling a destructor on an automated object is dangerous, as the second call (when the object goes out of scope) has undefined behaviour.
That is true. Undefined Behavor is invoked if you explicitly destroy an object with automatic storage. Learn more about it.
So I was lucky with my compiler (VS 2017) or this specific program.
I'd say you were unlucky. The best (for you, the coder) that can happen with UB is a crash at first run. If it appears to work fine, the crash could happen in January 19, 2038 in production.
Is the text simply wrong about the runtime error? Or is it really common to have runtime error? Or maybe my compiler implemented some kind of warding mechanism against this kind of things?
Yes, the text's kinda wrong. Undefined behavior is undefined. A run-time error is only one of many possibilities (including nasal demons).
A good read about undefined behavor: What is undefined behavor?
No this is simply undefined behavior from the draft C++ standard [class.dtor]p16:
Once a destructor is invoked for an object, the object no longer exists; the behavior is undefined if the destructor is invoked for an object whose lifetime has ended ([basic.life]).
[ Example: If the destructor for an automatic object is explicitly invoked, and the block is subsequently left in a manner that would ordinarily invoke implicit destruction of the object, the behavior is undefined.
— end example
and we can see from the defintion of undefined behavior:
behavior for which this document imposes no requirements
You can have no expectations as to the results. It may have behaved that way for the author on their specific compiler with specific options on a specific machine but we can't expect it to be a portable nor reliable result. Althought there are cases where the implementation does try to obtain a specific result but that is just another form of acceptable undefined behavior.
Additionally [class.dtor]p15 gives more context on the normative section I quote above:
[ Note: Explicit calls of destructors are rarely needed.
One use of such calls is for objects placed at specific addresses using a placement new-expression.
Such use of explicit placement and destruction of objects can be necessary to cope with dedicated hardware resources and for writing memory management facilities.
For example,
void* operator new(std::size_t, void* p) { return p; }
struct X {
X(int);
~X();
};
void f(X* p);
void g() { // rare, specialized use:
char* buf = new char[sizeof(X)];
X* p = new(buf) X(222); // use buf[] and initialize
f(p);
p->X::~X(); // cleanup
}
— end note ]
Is the text simply wrong about the runtime error?
It is wrong.
Or is it really common to have runtime error? Or maybe my compiler implemented some kind of warding mechanism against this kind of things?
You cannot know, and this is what happens when your code invokes Undefined Behavior; you don't know what will happen when you execute it.
In your case, you were (un)lucky* and it worked, while for me, it caused an error (double free).
*Because if you received an error you would start debugging, otherwise, in a large project for example, you might missed it...
Is there a way to make a destructor of a class NOT call the destructor of one of the class members and/or NOT call the destructor of its base class?
In case this is not possible, is creating certain class members with placement-new and destructing (/not-destructing) them manually a possible workaround? Thanks!
EDIT:
The reason I need this: Class C owns object M. M has a non-trivial destructor. C is friend of M and manages M in a way that there is no need to call M's destructor. It is OK to call it but it means performance overhead. (it's a problem in this case.)
I was thinking to make an a derived class from M that has a destructor that does nothing, but then that would still call the destructor of the base.
At construction time, C++ ensures that the subclasses contructors are first called, then the members are contructed, and finally the appropriate constructor is applied. At destruction time the symetric is done.
That means that you cannot prevent the application of a base class destructor, nor of any member constructor, as soon as the object is destructed. If you want to only destruct some, you must find a way to not destruct the object (just use a raw pointer...) and manually call destructors on what you want. But you certainly do not want to do that!
C++ is very confident on the programmer skills, so it is easy to write a program invoking undefined behaviour. If you find yourself trying to subvert the C++ compiler to not call the destructor of a base class or of a member, you have a major problem. The member you do not want to destroy should not be a member but more probably a pointer (raw or shared) or a reference to an external object that will have its own lifetime management. And the base class should probably also be a pointer or reference to an external object, and here again the lifetime can (and should) be managed outside of the class.
If the destructor has observable side-effects, then it would be undefined behaviour to end the lifetime of the object without invoking the destructor. This is covered in C++14 [basic.life]/4:
A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly calling the destructor for an object of a class type with a non-trivial destructor. For an object of a class type with a non-trivial destructor, the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released; however, if there is no explicit call to the destructor or if a delete-expression is not used to release the storage, the destructor shall not be implicitly called and any program that depends on the side effects produced by the destructor has undefined behavior.
So, there is no way to get around it. Perhaps you could redesign your code so that the destructor doesn't execute any unnecessary statements, or something.
This answer quotes C++11 Standard 3.8:
if there is no explicit call to the destructor or if a delete-expression (5.3.5) is not used to release the storage, the destructor shall not be implicitly called and any program that depends on the side effects produced by the destructor has undefined behavior.
The part about the destructor not being called is clear. Now suppose the skipped destructor had a side effect that should have affected the program behavior.
Why is the program behavior undefined now? Why wouldn't the side effects be skipped (since the destructor is not called) and the program run normally just without side effects applied?
The important part is the first part of that paragraph (emphasis mine):
A program may end the lifetime of any object by reusing the storage which the object occupies ...
If you simply reuse the storage for an object whose destructor has not been called, then you get undefined behaviour. For example, the object could have started a thread, or registered a callback, or some other action where an external component might expect the object to still exist.
In this case, we do have a precise answer. The specific line was introduced to resolve CWG 1116, "Aliasing of union members".
Your question does not make sense.
Why wouldn't the side effects be skipped (since the destructor is not called) and the program run normally just without side effects applied?
They are skipped, because they would have been triggered by the destructor and it has not been called.
My reading of:
and any program that depends on the side effects produced by the destructor has undefined behavior.
is simple, I view it in light of RAII. Example:
#include "Object.hpp"
struct Manager: private boost::noncopyable {
union Raw {
char _[sizeof(Object)];
Object o;
};
static Raw raw;
Manager() { new (raw.o) Object(); }
~Manager() { raw.o.~Object(); }
};
Now, if I allocate a Manager, forgets to destroy it, and allocates a new one, I am in a pinch for I am overwriting the storage of the first created Object with a second one even though it is still "alive". This is undefined behavior.
I believe this is put into the standard to allow for garbage collection. And to point out that C++ behaves differently that some other languages, by not calling destructors while collecting.
It specifically says that storage can be reused without calling the destructors of the objects in that memory area. If the program depends on the destructors being run, it will not work as expected.
If it doesn't depend on the destructors, all is fine.
Herb Sutter mentions in one of his http://www.gotw.ca articles that an object is constructed(has valid existence) only if the constructor executes completes.ie to put it in a crude way control passes beyond its final brace.
Now consider the following code
class A
{
public:
A()
{
f();
}
void f()
{
cout << "hello, world";
}
};
int main()
{
A a;
}
Now from what Herb says, can't we say that since A is not completely constructed inside its constructor Calling f() inside the constructor is invalid as the "this" ptr is not ready yet.
Still there is indeed a valid "this" inside the constructor and f() does get called.
I don't think Herb is saying something incorrect... but guess i am interpreting it incorrectly....can some explain to me what exactly that is?
Here is the link to the article : http://www.gotw.ca/gotw/066.htm
It talks about exceptions from constructors. Specifically here is the extract from it on which my question is based:
-When does an object's lifetime begin?
When its constructor completes successfully and returns normally. That is, control reaches the end of the constructor body or an earlier return statement.
-When does an object's lifetime end?
When its destructor begins. That is, control reaches the beginning of the destructor body.
Important point here is that the state of the object before its lifetime begins is exactly the same as after its lifetime ends -- there is no object, period. This observation brings us to the key question:
We might summarize the C++ constructor model as follows:
Either:
(a) The constructor returns normally by reaching its end or a return statement, and the object exists.
Or:
(b) The constructor exits by emitting an exception, and the object not only does not now exist, but never existed.
Now from what Herb says, can't we say
that since A is not completely
constructed inside its constructor
Calling f() inside the constructor is
invalid as the "this" ptr is not ready
yet.
That is only when f() is a virtual method of class A or its inheritance hierarchy and you expect the runtime resolution for f() according to the right object. In simple words, virtual mechanism doesn't kick in if the method is invoked inside constructor.
If f() is not a virtual function, there is no harm in calling it from constructor(s) provided you know what exactly f() does. Programmers usually call class methods like initialize() from constructor(s).
Can you give me the link to the Herb Sutter's article?
By the time program flow enters your constructor, the object's memory has been allocated and the this pointer is indeed valid.
What Herb means, is that the object's state may not have entirely initialized. In particular, if you are constructing a class derived from A, then that class' constructor will not have been called while you are still inside A's constructor.
This is important if you have virtual member functions, since any virtual function in the derived class will not be run if called from within A's constructor.
Note: it would have been easier with the exact article, so that we could have some context
Lifetime considerations are actually pretty complicated.
Considering the constructor of an object, there are two different point of views:
external: ie the user of an object
internal: ie, you when writing constructors and destructors (notably)
From the external point of view, the lifetime of an object:
begins once the constructor successfully completed
ends when the destructor begins to run
It means that if you attempt to access an object mid-construction or mid-destruction Bad Things Happen (tm). This is mostly relevant to multi-threaded programs, but may happen if you pass pointers to your object to base classes... which leads to...
...the internal point of view. It's more complicated. One thing you are sure of is that the required memory has been allocated, however parts of the objects may not be fully initialized yet (after all, you are constructing it).
in the body of the constructor, you can use the attributes and bases of the class (they are initialized), and call functions normally (virtual calls should be avoided).
if it's a base class, the derived object is not initialized yet (thus the restriction on virtual calls)
The implication from the lifetime not having started yet is mainly that, should the constructor throw an exception, the destructor will not be run.
Beware of member variables that are not yet initialized. Beware of virtual functions: the function that you call might not be the one that you expect if the function is virtual and a derived object is created. Other than that, I do not see any problem calling methods from the constructor. Especially the memory for the object has already been allocated.