Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Object creation order in braced init list

#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;
}

I've got 2 questions:

  • Why in first braced init list objects are created in right-to-left order?
  • Why parentheses in second case revert this order?

Edit: I've compiled it with msvs 2013

like image 483
sliser Avatar asked Jan 20 '14 12:01

sliser


People also ask

What is a braced init list?

Remember: using a braced-init-list means "initialize an object". What you are getting is an implicit conversion followed by an object initialization. You're getting "double user-conversion" because that's what you asked for.

How do you initialize a list in C++?

When do we use Initializer List in C++? Initializer List is used in initializing the data members of a class. The list of members to be initialized is indicated with constructor as a comma-separated list followed by a colon. Following is an example that uses the initializer list to initialize x and y of Point class.

What is member initializer list in C++?

Member initializer list is the place where non-default initialization of these objects can be specified. For bases and non-static data members that cannot be default-initialized, such as members of reference and const-qualified types, member initializers must be specified.

What is uniform initialization in C++?

Uniform initialization is a feature in C++ 11 that allows the usage of a consistent syntax to initialize variables and objects ranging from primitive type to aggregates. In other words, it introduces brace-initialization that uses braces ({}) to enclose initializer values.


2 Answers

In the second instance, you're actually only initialising with B(); through the use of the comma operator, A() was constructed and thrown away first.

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

On the other hand, in the first instance, you're initialising the C from both temporaries through an initializer list, whose elements should also be evaluated left-to-right, as it happens, but your compiler is buggy in this regard:

[C++11: 8.5.4/4]: Within the initializer-list of a braced-init-list, the initializer-clauses, including any that result from pack expansions (14.5.3), are evaluated in the order in which they appear. That is, every value computation and side effect associated with a given initializer-clause is sequenced before every value computation and side effect associated with any initializer-clause that follows it in the comma-separated list of the initializer-list. [ Note: This evaluation ordering holds regardless of the semantics of the initialization; for example, it applies when the elements of the initializer-list are interpreted as arguments of a constructor call, even though ordinarily there are no sequencing constraints on the arguments of a call. —end note ]

I can reproduce the problem with GCC 4.8*, but Clang 3.5 behaves properly. The bug has been discussed on the std-discussion list before&ddagger;, but I haven't found a GCC Bugzilla ID yet§.

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

*http://coliru.stacked-crooked.com/a/1f18e0d1f8973f3c
http://coliru.stacked-crooked.com/a/5a6e7506e9be97c3
&ddagger;https://groups.google.com/a/isocpp.org/forum/#!topic/std-discussion/TQUnBFkUBDg
§#51253 may be related.

like image 165
Lightness Races in Orbit Avatar answered Nov 08 '22 03:11

Lightness Races in Orbit


Why in first braced init list objects are created in right-to-left order?

No. It is left-to-right. Your compiler has bug which is why it is evaluating right-to-left. GCC (4.8) is known to have this bug. Do you use GCC?

Why parentheses in second case revert this order?

Same. Left to right. In this case, comma operator comes into picture, which evaluates operands left-to-right.

like image 39
Nawaz Avatar answered Nov 08 '22 01:11

Nawaz