C++ C++;std::元组破坏顺序

C++ C++;std::元组破坏顺序,c++,c++11,std,stdtuple,C++,C++11,Std,Stdtuple,是否有一条规则规定std::tuple的成员按什么顺序销毁 例如,如果Function1将std::tuple返回到Function2,那么我是否可以确保(当Function2的范围保留时)第二个成员引用的ClassB实例在第一个成员引用的ClassA实例之前被销毁 std::tuple< std::unique_ptr< ClassA >, std::unique_ptr< ClassB > > Function1() { std::tuple<

是否有一条规则规定std::tuple的成员按什么顺序销毁

例如,如果
Function1
std::tuple
返回到
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?
}
std::tuple,std::unique_ptr>Function1()
{
std::tuple,std::unique\u ptr>垃圾;
获取(垃圾)。重置(/*…*/);
获取(垃圾)。重置(/*…*/);
回收垃圾;
}
无效函数2()
{
自动销毁=功能1();
//…做点别的
//被破坏的范围
//ClassB实例是否在ClassA实例之前被销毁?
}

对于Clang 3.4,我对
std::pair
和2元素
std::tuple
得到了相同的销毁顺序,而对于g++5.3,我得到了相反的顺序,这可能主要是由于在libstd++中递归实现了
std::tuple

所以,它基本上可以归结为我在评论中所说的,它是实现定义的

从报告中可以看出:

Martin Sebor的评论

由于std::pair成员的布局是完全指定的,所以 初始化和销毁的顺序。测试的输出 本案反映了这一顺序

std:stuple子对象的初始化(和销毁)顺序 没有那么明确的规定。至少从现在来看还不明显 如果需要任何特殊订单,请阅读规范

使用libstdc++输出std::tuple的原因与此相反 之所以使用std::pair是因为实现依赖于递归 继承,以相反的方式存储和构造元组元素 顺序:即存储最后一个元素的基类 首先构造,然后是每个派生类(每个 存储最后一个元素(第n个元素)

错误报告者引用的标准[第20.4.1节]中的引用

1本小节描述了提供元组的元组库 类型为类模板元组,可以使用任何 参数的数量。每个模板参数都指定模板的类型 元组中的元素。因此,元组是异构的, 固定大小的值集合具有两个参数的元组的实例化 参数类似于具有相同两个参数的pair的实例化 参数。见20.3

链接错误中对此提出的反对意见如下:

被描述为相似并不意味着它们在每个方面都是相同的 细节std::pair和std::tuple是具有不同属性的不同类 对每一项的要求。如果您认为要求员工表现良好 在这方面相同(即,将其子对象定义在 相同的顺序)您需要指出 我保证


对于你的问题,我将提供我学到的人生课程,而不是直接的回答:

如果您可以为多个备选方案制定一个合理的论据,说明为什么该备选方案应为本标准规定的备选方案,那么您不应假设其中任何一个备选方案是强制性的(即使其中一个恰好是强制性的)

在元组上下文中-请,请善待维护代码的人员,不要让元组元素的销毁顺序潜在地破坏其他元素的销毁。那太邪恶了。。。想象一下,一个倒霉的程序员需要调试这个东西。事实上,那可怜的灵魂可能在几年后变成你自己,那时你已经忘记了你那聪明的把戏


如果您绝对必须依赖于销毁顺序,那么您可能应该使用一个适当的类,将元组的元素作为其数据成员(您可以为其编写一个析构函数,明确需要以什么顺序发生什么),或者有助于更明确地控制销毁的其他安排。

标准没有规定
std::tuple
的销毁顺序。§20.4.1/p1规定:

具有两个参数的元组的实例化类似于 具有相同两个参数的对的实例化

相似在这里不被解释为相同,因此并不意味着
std::tuple
的参数的销毁顺序应该相反

鉴于
std::tuple
的递归性质,最可能的情况是破坏顺序与其参数顺序一致

我的假设也基于bug报告,在讨论中,我的上述假设是合理的


也就是说,
std::tuple
的销毁顺序未指定。

我猜这主要取决于标准库中如何实现
std::tuple
。我在规范中找不到任何指定
std::tuple
销毁顺序的内容。可能应该以未指定的形式提交。最近,Antony Polukhin的excellet CPPCon 2016中提到了这个问题,即在没有适当语言支持的情况下,在C++14中实现部分反射。IIRC他说他唯一可怕的事情是重新实现std::tuple来强制执行特定的初始化顺序。还有,ping@101010。你怎么知道
std::pair
元素的销毁顺序是相反的?类似!=identical.@deepmax基于libcxx和libstd++for std::pair上的实现。@101010我不知道,我认为雷同类似于雷同。@yakk非常类似于雷同,但不完全相同于雷同:)这是一堂非常重要的课!当程序