C++ std::tuple 破坏顺序
C++ std::tuple order of destruction
是否有规定 std::tuple 的成员被销毁的顺序?
例如,如果 Function1
returns 一个 std::tuple<std::unique_ptr<ClassA>, std::unique_ptr<ClassB>>
到 Function2
,那么我可以确定吗(当 Function2
的范围被保留时)第二个成员引用的 ClassB
实例在第一个成员引用的 ClassA
实例之前销毁?
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?
}
在 Clang 3.4 中,std::pair
和 2 个元素 std::tuple
的销毁顺序相同,而在 g++ 5.3 中,我得到的顺序相反,这可能主要是由于 [=11 的递归实现=] 在 libstd++ 中。
所以,基本上归结为我在评论中所说的,它是实现定义的。
来自 BUG 报告:
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).
错误报告者引用的标准[第 20.4.1 节]中的引述
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.
链接错误中反对此的论点是:
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.
我将提供我学到的人生教训,而不是直接回答你的问题:
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).
在元组的上下文中 - 请善待维护您代码的人员,不要让元组元素的销毁顺序潜在地扰乱其他元素的销毁。那太邪恶了……想象一下需要调试这个东西的倒霉的程序员。事实上,几年后那个可怜的灵魂可能就是你自己,那时你已经忘记了当年的聪明把戏。
如果您绝对必须依赖销毁顺序,也许您应该使用适当的 class 并将元组的元素作为其数据成员(您可以为其编写析构函数,明确需要什么以什么顺序发生),或其他一些有助于更明确地控制销毁的安排。
标准没有指定 std::tuple
的销毁顺序。 §20.4.1/p1 规定的事实:
An instantiation of tuple with two arguments is similar to an
instantiation of pair with the same two arguments.
Similar 这里不解释为 identical 因此并不暗示 std::tuple
应该有一个反向销毁顺序它的参数。
鉴于 std::tuple
的递归性质,最有可能的是销毁顺序与其参数的顺序一致。
我的假设也基于 GCC BUG 66699 的错误报告,在讨论中我的上述假设是合理的。
也就是说,std::tuple
的销毁顺序未指定。
是否有规定 std::tuple 的成员被销毁的顺序?
例如,如果 Function1
returns 一个 std::tuple<std::unique_ptr<ClassA>, std::unique_ptr<ClassB>>
到 Function2
,那么我可以确定吗(当 Function2
的范围被保留时)第二个成员引用的 ClassB
实例在第一个成员引用的 ClassA
实例之前销毁?
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?
}
在 Clang 3.4 中,std::pair
和 2 个元素 std::tuple
的销毁顺序相同,而在 g++ 5.3 中,我得到的顺序相反,这可能主要是由于 [=11 的递归实现=] 在 libstd++ 中。
所以,基本上归结为我在评论中所说的,它是实现定义的。
来自 BUG 报告:
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).
错误报告者引用的标准[第 20.4.1 节]中的引述
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.
链接错误中反对此的论点是:
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.
我将提供我学到的人生教训,而不是直接回答你的问题:
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).
在元组的上下文中 - 请善待维护您代码的人员,不要让元组元素的销毁顺序潜在地扰乱其他元素的销毁。那太邪恶了……想象一下需要调试这个东西的倒霉的程序员。事实上,几年后那个可怜的灵魂可能就是你自己,那时你已经忘记了当年的聪明把戏。
如果您绝对必须依赖销毁顺序,也许您应该使用适当的 class 并将元组的元素作为其数据成员(您可以为其编写析构函数,明确需要什么以什么顺序发生),或其他一些有助于更明确地控制销毁的安排。
标准没有指定 std::tuple
的销毁顺序。 §20.4.1/p1 规定的事实:
An instantiation of tuple with two arguments is similar to an instantiation of pair with the same two arguments.
Similar 这里不解释为 identical 因此并不暗示 std::tuple
应该有一个反向销毁顺序它的参数。
鉴于 std::tuple
的递归性质,最有可能的是销毁顺序与其参数的顺序一致。
我的假设也基于 GCC BUG 66699 的错误报告,在讨论中我的上述假设是合理的。
也就是说,std::tuple
的销毁顺序未指定。