首页 文章

C std :: tuple破坏顺序

提问于
浏览
46

有一条规则说明std :: tuple的成员被破坏了吗?

例如,如果 Function1std::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?
}

3 回答

  • 53

    该标准未指定 std::tuple 的销毁顺序 . §20.4.1/ p1指定的事实是:

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

    Similar 此处未被解释为 identical ,因此并不暗示 std::tuple 应具有其参数的反向销毁顺序 .

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

    我的假设基于GCC BUG 66699的错误报告,在讨论中我的假设是合理的 .

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

  • 35

    为了回答你的问题,我将提供一个我学到的生活课程,而不是直接的答案:

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

    在元组的上下文中 - 请,请善待维护代码的人,不要让元组元素的破坏顺序可能破坏其他元素的破坏 . 那只是邪恶的......想象一下需要调试这个东西的不幸的程序员 . 事实上,这个可怜的灵魂可能会在几年内成为你自己,当时你已经忘记了当时的巧妙伎俩 .

    如果你绝对必须依赖于破坏顺序,也许你应该只使用一个正确的类,将元组的元素作为其数据成员(你可以编写一个析构函数,明确需要以什么顺序发生的事情),或者其他一些安排有助于更明确地控制破坏 .

  • 13

    使用Clang 3.4,我得到了 std::pair 和2个元素 std::tuple 的相同销毁顺序,并且使用g 5.3我得到相反的顺序,这可能主要是由于libstd中 std::tuple 的递归实现 .

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

    来自BUG报告:

    Martin Sebor的评论

    由于完全指定了std :: pair成员的布局,因此初始化和销毁的顺序也是如此 . 测试用例的输出反映了此顺序 . std:stuple子对象的初始化(和销毁)顺序没有明确规定 . 如果需要任何特定订单,至少从我对规范的阅读中看不出来 . 使用libstdc的std :: tuple的输出与std :: pair相反的原因是因为依赖于递归继承的实现以相反的顺序存储和构造元组元素:即基类,它存储了最后一个元素,首先存储和构造,然后是每个派生类(每个派生类存储最后一个 - 第N个元素) .

    臭虫记者引用的标准[第20.4.1节]的引用

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

    在链接的bug中对此进行的争论是:

    被描述为相似并不意味着它们在每个细节上都是相同的 . std :: pair和std :: tuple是不同的类,每个类都有不同的要求 . 如果您认为在这方面需要表现相同(即,以相同的顺序定义其子对象),则需要指出保证它的特定措辞 .

相关问题