struct Base {
Base() {
std::cout << "Inside: " << __PRETTY_FUNCTION__ << std::endl;
}
~Base() {
std::cout << "Inside: " << __PRETTY_FUNCTION__ << std::endl;
}
};
struct BaseWrapper {
const Base &b;
};
int main()
{
{
auto *w = new BaseWrapper{{}};
std::cout << "Inside: " << __PRETTY_FUNCTION__ << std::endl;
delete w;
}
return 0;
}
The above code works as I expected when I compile it with C++11 or C++14, but when I compile it with C++17, it gives me something like this:
Inside: Base::Base()
Inside: int main()
As you can see, Base::~Base() was never called. Which doesn't make much sense to me. I have tested this code with GCC 7.3.0 on Ubuntu 18.04.1 LTS, and also with OnlineGDB. They all give the same result.
I'm just wondering if this is a new feature in C++17 or it is a bug?
Update:
I'm well aware that w->b
is a dangling reference. Actually, I deliberately wrote this piece of code just to show that. Then, I found this issue while testing it.
What I really want to know is how severe this issue is, in case I have to stick with GCC 7.3? or if there is any other ways to reproduce the same issue? or the defect report?
Clearly, a temporary that is created but not destroyed is a compiler bug - unless the standard says the behaviour is undefined. The example is well defined however. The relevant rules from the standard [class.temporary]:
When an implementation introduces a temporary object of a class that has a non-trivial constructor ([class.default.ctor], [class.copy.ctor]), it shall ensure that a constructor is called for the temporary object. Similarly, the destructor shall be called for a temporary with a non-trivial destructor ([class.dtor]). Temporary objects are destroyed as the last step in evaluating the full-expression ([intro.execution]) that (lexically) contains the point where they were created. ...
There are three contexts in which temporaries are destroyed at a different point than the end of the full-expression. ...
The third context is when a reference is bound to a temporary object ...
The exceptions to this lifetime rule are:
...
A temporary bound to a reference in a new-initializer ([expr.new]) persists until the completion of the full-expression containing the new-initializer.