对象创建订单在支撑初始化列表中

Object creation order in braced init list

本文关键字:初始化 列表 创建 对象      更新时间:2023-10-16
#include <iostream>
struct A
{
    A() { std::cout << "(A::A)"; }
};
struct B
{
    B() { std::cout << "(B::B)"; }
};
struct C
{
    template<typename ...Args>
    C(Args && ...) {}
};
int main(int agrc, char *argv[])
{
    C {A(), B()}; // <-- prints (B::B)(A::A)
    std::cout << std::endl;
    C {(A(), B())}; // <-- prints (A::A)(B::B)
    std::cout << std::endl;
    return 0;
}

我有2个问题:

  • 为什么在第一个支撑启动列表中以左顺序创建对象?
  • 为什么在第二种情况下括号还原?

编辑:我已将其编译为MSVS 2013

在第二个实例中,实际上您仅使用B()初始化;通过使用逗号操作员A()首先构造并扔掉。

C {(A(), B())};
//|^^^^^^^^^^|
//      --------> (A(), B())
//                  ^^^  ^^^
//                   |    |
//                   /    
//            evaluated,   THEN evaluated,
//            discarded      used

另一方面,首先,您是通过 emarties einitializer列表来初始化的 C,当时还应将其元素从左到右进行评估,但是您的编译器在这方面是越来越大的:

[C++11: 8.5.4/4]: braced-init-list initializer-clauses initializer-list ,包括包装扩展产生的任何结果(14.5.3),以它们出现的顺序进行评估。也就与任何 initializer-clause 相关的值计算和副作用,这些 initizer-initiber-list-list-list 的逗号分隔列表中。 [注意:此评估顺序不管初始化的语义如何;例如,当 initiber-list 的元素被解释为构造函数调用的参数时,它也适用,尽管通常对调用的参数没有测序约束。 - end Note]

我可以用GCC 4.8 *重现问题,但是Clang 3.5行为正确&Dagger; 。该错误已在&ddagger; 之前的 std-discussion 列表上进行了讨论,但是我还没有找到GCC Bugzilla ID &sect>&sect;

C {A(), B()};
// ^^^  ^^^
//  |    
// eval-  THEN
// uated   evaluated
//         /
//        /
//  both used

* http://coliru.stacked-crooked.com/a/a/1f18e0d1f8973f3f3c

&Dagger; http://coliru.stacked-crooked.com/a/a/5a6e7506e9be97c3

&Ddagger; https://groups.google.com/a/isocpp.org/forum/# !! Topic/std-discussion/tqunbfkubdg

&sect; #51253可能是相关的。

为什么在第一个支撑启动列表中以左顺序创建对象?

否。它是从左到右的。您的编译器有错误,这就是为什么它正在评估左右的原因。已知 GCC(4.8)具有此错误。您是否使用GCC?

为什么在第二种情况下括号还原?

相同。左到右。在这种情况下,逗号操作员会出现图片,该操作数从左到右评估。

它是GCC 4.8.1(我想您使用GCC)或其他编译器的旧错误。我几个月前写了这个错误初始化列表:GCC 4.8.1

的错误

尽管它是用俄语编写的,但您可以使用例如Google服务翻译将其翻译成英文。

由初始化列表的其他元素从左到右评估,并在评估下一个元素之前应用所有副作用。

在第二个代码示例中,您实际上将构造函数称为conma运算符的表达式。逗号运算符的行为与初始器列表相同的方式是它从左到右评估其操作数,并在评估下一个操作数之前应用副作用。