Copy elision for list-initialization, where is it stated in the standard?
Asked Answered
E

1

14

In [dcl.init]/17.6, it is explicitly written that for the case of parenthesis initialization, copy elision occurs:

If the initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the class of the destination, the initializer expression is used to initialize the destination object. [ Example: T x = T(T(T())); calls the T default constructor to initialize x.  — end example ]

But in the case of list-initialization, for which the above paragraph does not apply, I did not find anything similar. See [dcl.init.list].

So why is there copy elision in this case: T x{T(T())}; according to the C++17 standard.

Eighteenmo answered 28/3, 2018 at 12:52 Comment(1)
related question: #68436637Champaign
J
5

There is no copy elision in such case according to the current draft.

Consider the following example:

#include <iostream>
#include <initializer_list>

struct S {
    S() {std::cout << "default\n";}
    S(const S&) {std::cout << "copy\n";}
    S(std::initializer_list<S>) {std::cout << "initializer list\n";}
};

int main()
{
    S s = S{S()};
}

According to Core Language Issue 2137, the constructor taking std::initializer_list as parameter should be chosen (Clang may choose copy constructor or perform copy elision here, which is incorrect). So constructors are intended to be taken into consideration for such list initialization.

The problem is that when copy/move constructor is selected, it is reasonable to elide this copy/move. In fact, Core Language Issue 2327 has already addressed this defect.

Juarez answered 28/3, 2018 at 13:47 Comment(4)
This is realy unfortunate, this core language issue resolution addresses a very singular case, and disabled a very frequent copy-elision, that everybody expects. This is realy bad!! Hopefuly both GCC and Clang do the copy elision if there are no maching initializer list constructor.Eighteenmo
I don't get it. This seems to be a special case for initializer_list, but the OP seems to be asking about the general case of a brace-init-list. In fact, I think the conditions from text quoted by the OP do not apply for your example, because initializer_list<S> is not the same type as S. Bottom line: Your example does not prove that this rule could not be applied for brace-init-list. Issue 2327 seems to be about a slightly different case as well, which is that of an implicit user-defined conversion.Escapism
@ArneVogel I mean there cannot be a copy elision for general cases, otherwise the special case cannot be handled correctly. Issue 2327 is talking about a more general issue. You can see more details in this answer.Juarez
Just for documentation, (since I lost my time on it, I share it in case you are working with the commitee): GCC 7.3 selects the initializer_list constructor if it exists but does the copy elision if no init.list. constructor, Clang does not select the initializer list constructor and always elide the copy constructor, ICC 18 elides the copy constructor only if not using list-initialization as stated by the standard but does not select the initializer list constructor if it exists, MSVC 19 does not seem to implement C++17 prvalue. compiler explorerEighteenmo

© 2022 - 2024 — McMap. All rights reserved.