yggdrasil
yggdrasil

Reputation: 757

brace initializer list as function argument

Ignoring the copy/move elision from the compiler, I would like to know if the following code (assuming foo has a constructor accepting three ints) "syntactically" creates a temporary object and then copy/move initializes the function argument, or directly calls the constructor:

void acceptsFoo(foo a);

acceptsFoo({1, 2, 3});

And what about this case?

//ignoring RVO optimization
foo returnsFoo()
{
   return {1, 2, 3};
}

I know that the code below, even without copy/move elision, is the same as calling the constructor so will not generate any temporary, but I couldn't find info about the code above.

foo = { 1, 2, 3 } //assuming the constructor is non-explicit
foo { 1, 2, 3 }

Upvotes: 1

Views: 2491

Answers (2)

eerorika
eerorika

Reputation: 238301

void acceptsFoo(foo a);

acceptsFoo({1, 2, 3});

No, there would not be a temporary in this case. The parameter is initialized directly from the argument expression.


//ignoring RVO optimization
foo returnsFoo()
{
   return {1, 2, 3};
}

Just like in the case of the argument, the return value is initialized directly from the return-statement.

However, the result of the function call expression would be a temporary object, yes. So, if you called the function like this: foo f = returnsFoo(); There would be two instances created. First the return value is initialized from the brace-initializer, then the variable bound object is copy initialized from the temporary (by move, if foo is movable).

That is from the perspective of the abstract machine; the copy/move could be elided in practice (this is what RVO does).


However starting from C++17, in the statement foo f = returnsFoo();, there would be no temporary and no copy/move to elide. On the other hand, in the statement returnsFoo();, there would be a temporary created (which is destroyed immediately).

Upvotes: 2

Nicol Bolas
Nicol Bolas

Reputation: 473212

When a braced-init-list is used to initialize an object, it is used to initialize the object. Period.

Applying a braced-init-list to a function parameter means to initialize that parameter with the list of values, in accord with the rules of list initialization. When you return a braced-init-list, it is used to initialize the return value object with the list of values, in accord with the rules of list initialization.

There is no temporary object theoretically being copied into the parameter/return value.

Now (pre-C++17), if you had done acceptsFoo(foo{1, 2, 3}); or return foo{1, 2, 3}, then that would provoke the creation of a temporary, which would then be used to initialize the parameter/return value.

Upvotes: 2

Related Questions