Guaranteed copy elision and Nonmoveable{Nonmoveable{}}
Asked Answered
A

1

6

I found GCC 7 has implemented guaranteed copy elision, and I tried the code below in wandbox:

#include <iostream>

struct NonMovable
{
    NonMovable() noexcept = default;
    NonMovable(NonMovable&&) noexcept = delete;
    NonMovable& operator=(NonMovable&&) noexcept = delete;
};

NonMovable Make()
{
    return {};
}


int main()
{
    //[[maybe_unused]] const auto x = Make();
    //const auto z = NonMovable{};
    [[maybe_unused]] const auto y = NonMovable{NonMovable{}};
}

And I got compile error:

prog.cc: In function 'int main()':
prog.cc:20:60: error: use of deleted function 'NonMovable::NonMovable(NonMovable&&)'
     [[maybe_unused]] const auto y = NonMovable{NonMovable{}};
                                                            ^
prog.cc:6:5: note: declared here
     NonMovable(NonMovable&&) noexcept = delete;
     ^~~~~~~~~~

According to cppreference:

In initialization, 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:
T x = T(T(T())); // only one call to default constructor of T, to initialize x

So I think it should be equal to const Movable y{};. What's wrong?

Aqua answered 7/10, 2016 at 15:32 Comment(1)
It seems that it's a bug of GCC. The code compiles well on a new build of GCC.Aqua
C
1

List-initialization gives you no precise control over what happens. Basically the committee has guessed what the programmer might want to do most probably and assigned the corresponding meanings.

If you want to have precise control, use non-list initialization. For that, your testcase should work definitely.

If you stick to list-initialization, then for aggregates, I think current draft wording will do it and applies guaranteed copy "elision", because they say

If T is an aggregate class and the initializer list has a single element of type cv U, where U is T or a class derived from T, the object is initialized from that element (by copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization).

In addition, you might get what you want in a future revision of the Standard or in a defect report resolution even for non-aggregates. I believe that your class is an aggregate, so it should compile. But perhaps there's something I'm missing here.

Characharabanc answered 7/10, 2016 at 16:10 Comment(1)
" use non-list initialization. " would be const auto y = NonMovable(NonMovable()); ? If so, that doesn't seem to work either.Electroacoustics

© 2022 - 2024 — McMap. All rights reserved.