Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are function return values automatic objects and thus guaranteed to be destructed?

In [except.ctor] the standard (N4140) guarantees that:

...destructors are invoked for all automatic objects constructed since the try block was entered...

However in the following example the empty output proves that the return value of function foo is not destructed, although it has been constructed. Compiled using g++ (5.2.1) and clang++ (3.6.2-1) and with options -O0 -fno-elide-constructors -std=c++14.

struct A { ~A() { cout << "~A\n"; } };  struct B { ~B() noexcept(false) { throw 0; } };  A foo() {   B b;   return {}; }  int main() {   try { foo(); }   catch (...) { } } 

Is this a bug both in g++ and clang++, or are function return values not considered automatic objects, or is it a loop hole in the C++ language?

In none of [stmt.return], [expr.call] or [dcl.fct] I have been able to find a clear statement whether a function return value is considered an automatic object. The closest hints I found are 6.3.3 p2:

...A return statement can involve the construction and copy or move of a temporary object...

and 5.2.2 p10:

A function call is an lvalue if the result type is an lvalue reference type or an rvalue reference to function type, an xvalue if the result type is an rvalue reference to object type, and a prvalue otherwise.

like image 934
Florian Kaufmann Avatar asked Jan 08 '16 09:01

Florian Kaufmann


People also ask

Can a destructor return a value?

Declaring destructorsDo not return a value (or void ). Cannot be declared as const , volatile , or static . However, they can be invoked for the destruction of objects declared as const , volatile , or static .

What's the order in which the local objects are destructed?

What's the order that local objects are destructed? ¶ Δ In reverse order of construction: First constructed, last destructed.

Why is it necessary to do something to the value returned by a function?

This is done so that there is a definitive ending point for the function. It is mainly to increase readability and to help future programmers to understand what you were trying to do. There should be no assumption about what a function returns.

Why destructor is used when delete is there?

When delete is used to deallocate memory for a C++ class object, the object's destructor is called before the object's memory is deallocated (if the object has a destructor). If the operand to the delete operator is a modifiable l-value, its value is undefined after the object is deleted.


Video Answer


2 Answers

Function return values are considered temporaries, and the construction of the return value is sequenced before the destruction of locals.

Unfortunately, this is underspecified in the standard. There is an open defect which describes this and offers some wording to fix the issue

[...] A return statement with an operand of type void shall be used only in a function whose return type is cv void. A return statement with any other operand shall be used only in a function whose return type is not cv void; the return statement initializes the object or reference to be returned by copy-initialization (8.5 [dcl.init]) from the operand. [...]

The copy-initialization of the returned entity is sequenced before the destruction of temporaries at the end of the full-expression established by the operand of the return statement, which, in turn, is sequenced before the destruction of local variables (6.6 [stmt.jump]) of the block enclosing the return statement.

Since function return values are temporaries, they aren't covered by the destructors are invoked for all automatic objects quote at the start of your post. However, [class.temporary]/3 says:

[...] Temporary objects are destroyed as the last step in evaluating the full-expression that (lexically) contains the point where they were created. This is true even if that evaluation ends in throwing an exception. [...]

So I think you could consider this a bug in GCC and Clang.

Don't throw from destructors ;)

like image 144
TartanLlama Avatar answered Sep 24 '22 22:09

TartanLlama


This is a bug, and for once, MSVC actually gets it right: it prints "~A".

like image 32
Sebastian Redl Avatar answered Sep 21 '22 22:09

Sebastian Redl