C++ std::tuple order of destruction

C++C++11StdStdtuple

C++ Problem Overview


Is there a rule which states in which order the members of an std::tuple are destroyed?

For example if Function1 returns an std::tuple<std::unique_ptr<ClassA>, std::unique_ptr<ClassB>> to Function2, then can I be sure that (when the scope of Function2 is left) the instance of ClassB referred to by the second member is destroyed before the instance of ClassA referred to by the first member?

std::tuple< std::unique_ptr< ClassA >, std::unique_ptr< ClassB > > Function1()
{
    std::tuple< std::unique_ptr< ClassA >, std::unique_ptr< ClassB > > garbage;
    get<0>(garbage).reset( /* ... */ );
    get<1>(garbage).reset( /* ... */ );
    return garbage;
}

void Function2()
{
    auto to_be_destroyed = Function1();
    // ... do something else

    // to_be_destroyed leaves scope
    // Is the instance of ClassB destroyed before the instance of ClassA?
}

C++ Solutions


Solution 1 - C++

I'll offer a life lesson I've learned, rather than a direct answer, in response to your question:

>If you can formulate, for multiple alternatives, a reasonable argument for why that alternative should be the one mandated by the standard - then you should not assume any of them is mandated (even if one of them happens to be).

In the context of tuples - please, please be kind to the people maintaining your code and do not allow the destruction order of tuple elements to potentially mess up the destruction of other elements. That's just evil... imagine the hapless programmer who will need to debug this thing. In fact, that poor soul might be yourself in a few years, when you've already forgotten about your clever trick from back-in-the-day.

If you absolutely must rely on destruction order, perhaps you should just be using a proper class with the tuple's elements as its data members (which you could write a destructor for, making it clear what needs to happen in what order), or some other arrangement facilitating a more explicit control of the destruction.

Solution 2 - C++

The standard doesn't specify the order of destruction for std::tuple. The fact that §20.4.1/p1 specifies that:

> An instantiation of tuple with two arguments is similar to an > instantiation of pair with the same two arguments.

Similar here is not interpreted as identical and consequently it's not implied that std::tuple should have a reverse destruction order of its arguments.

Given the recursive nature of std::tuple most probable is that the order of destruction is in order with the order of its arguments.

I also base my assumptions on a bug report for GCC BUG 66699 where in the discussion my assumptions above are justified.

That said, the order of destruction for std::tuple is unspecified.

Solution 3 - C++

With Clang 3.4 I get the same destruction order for both std::pair and 2 element std::tuple and with g++ 5.3 I get opposite order which could be mainly due to the recursive implementation of std::tuple in libstd++.

So, it basically boils down to what I said in the comment, it is implementation defined.

From the BUG report:

Comment by Martin Sebor

> Since the layout of std::pair members is fully specified, so is the > order of their initialization and destruction. The output of the test > case reflects this order. > > The order of initialization (and destruction) of std:stuple subobjects > is less clearly specified. At least it's not immediately obvious from > my reading of the spec if any particular order is required. > > The reason why the output for std::tuple with libstdc++ is the reverse > of std::pair is because the implementation, which relies on recursive > inheritance, stores and constructs tuple elements in the reverse > order: i.e., the base class, which stores the last element, is stored > and constructed first, followed by each derived class (each of which > stores the last - Nth element).

The quote from standard [section 20.4.1] which the bug reporter is quoting to

> 1 This subclause describes the tuple library that provides a tuple > type as the class template tuple that can be instantiated with any > number of arguments. Each template argument specifies the type of an > element in the tuple. Consequently, tuples are heterogeneous, > fixed-size collections of values. An instantiation of tuple with two > arguments is similar to an instantiation of pair with the same two > arguments. See 20.3.

Argument against this made in the linked bug is:

> Being described as similar doesn't imply they are identical in every > detail. std::pair and std::tuple are distinct classes with different > requirements on each. If you believe the are required to behave > identically in this respect (i.e., have their subobjects defined in > the same order) you need to point to the specific wording that > guarantees it.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionz32a7ulView Question on Stackoverflow
Solution 1 - C++einpoklumView Answer on Stackoverflow
Solution 2 - C++101010View Answer on Stackoverflow
Solution 3 - C++ArunmuView Answer on Stackoverflow