Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Class with all automatically-generated constructors/operators deleted can still be returned from a function?

Recently, I came across this answer which describes how to initialize a std::array of non-default-constructible elements. I was not so surprised because that answer clearly doesn't do any default-constructing.

Instead, it is constructing a temporary std::array using aggregate initialization, then moving (if the move constructor is available) or copying into the named variable when the function returns. So we only need either the move constructor or copy constructor to be available.

Or so I thought...

Then came this piece of code which confounded me:

struct foo {
    int x;
    foo(int x) : x(x) {}
    foo() = delete;
    foo(const foo&) = delete;
    foo& operator=(const foo&) = delete;
    foo(foo&&) = delete;
    foo& operator=(foo&&) = delete;
};

foo make_foo(int x) {
    return foo(x);
}

int main() {
    foo f = make_foo(1);
    foo g(make_foo(2));
}

All the five special member constructors/operators are explicitly deleted, so now I shouldn't be able to construct my object from a return value, correct?

Wrong.

To my surprise, this compiles in gcc (with C++17)!

Why does this compile? Clearly to return a foo from the function make_foo(), we have to construct a foo. Which means that in the main() function we are assigning or constructing a foo from the returned foo. How is that possible?!

like image 737
Bernard Avatar asked Jul 20 '18 13:07

Bernard


People also ask

Is copy constructor automatically generated?

No copy constructor is automatically generated.

Can we delete constructor in C++?

In another way, = delete means that the compiler will not generate those constructors when declared and this is only allowed on copy constructor and assignment operator. There is also = 0 usage; it means that a function is purely virtual and you cannot instantiate an object from this class.

What is a deleted function C++?

Deleted function declaration is a new form of function declaration that is introduced into the C++11 standard. To declare a function as a deleted function, you can append the =delete; specifier to the end of that function declaration. The compiler disables the usage of a deleted function.

What does default mean in C++?

A default argument is a value provided in a function declaration that is automatically assigned by the compiler if the calling function doesn't provide a value for the argument. In case any value is passed, the default value is overridden.


1 Answers

Welcome to the wonderful world of guaranteed copy elision (new to C++17. See also this question).

foo make_foo(int x) {
    return foo(x);
}

int main() {
    foo f = make_foo(1);
    foo g(make_foo(2));
}

In all of these cases, you're initializing a foo from a prvalue of type foo, so we just ignore all the intermediate objects and directly initialize the outermost object from the actual initializer. This is exactly equivalent to:

foo f(1);
foo g(2);

We don't even consider move constructors here - so the fact that they're deleted doesn't matter. The specific rule is [dcl.init]/17.6.1 - it's only after this point that we consider the constructors and perform overload resolution.

like image 139
Barry Avatar answered Oct 06 '22 00:10

Barry