问题
I want to know when copy/move elision applies (or is allowed to apply) to explicitly delete
d copy/move constructors and to non-delete
d copy/move constructors. Here are the specifics:
Can an explicitly
delete
d copy ctor or move ctor get elided? Is an attempt to construct an object from another same-type object or temporary object ever allowed to succeed by skipping over thedelete
d copy ctor and/ordelete
d move ctor?Here’s what happens in VC12 (with which I’m not sure if there is an option to disable copy/move elision):
#include <iostream> struct Foo { Foo() { std::cout << "default ctor\n"; } Foo(Foo const&) = delete; Foo(Foo&&) = delete; }; int main() { // ----Output------ Foo{ Foo() }; // "default ctor" Foo f; // "default ctor" Foo{ std::move(f) }; // error C2280: 'Foo::Foo(Foo &&)' : attempting to reference a deleted function Foo{ f }; // error C2280: 'Foo::Foo(const Foo &)' : attempting to reference a deleted function }
Even though IntelliSense complains about
Foo{ Foo() };
:Error: function “Foo::Foo(Foo &&)” ... cannot be referenced – it is a deleted function
, the compiler doesn't complain there, so that line still compiles.Why does
Foo{ Foo() };
work, but notFoo{ std::move(f) };
? If one call elides the move ctor, then shouldn’t the other?Why does
Foo{ Foo() };
work, but notFoo{ f };
? This selectivity looks arbitrary. This kind of arbitrary preference of rvalue reference over const reference (or vice versa) doesn’t seem to apply to non-ctor methods; where in a call, if adelete
d overload that would otherwise have a higher overload resolution priority than a non-delete
d overload, thedelete
d one blocks the non-delete
d one, resulting in a compiler error:struct Bar { void g(int const&) {} void g(int&&) = delete; }; //… Bar b; b.g(2); //error C2280: 'void Bar::g(int &&)' : attempting to reference a deleted function // ^ Would have compiled had function `g(int&&)` been commented out.
According to that logic, a
delete
dFoo(Foo&&)
shouldn’t block a call toFoo(Foo const&)
when the argument is not a temporary;Foo(Foo&&)
would have a lower overload resolution priority thanFoo(Foo const&)
in that case.I tried the same
Foo
example in g++ 4.8 with copy elision disabled (via the flag-fno-elide-constructors
) and again with it enabled. Both g++ trials gave:error: use of deleted function 'Foo::Foo(Foo&&)'
forFoo{ Foo() };
anderror: use of deleted function 'Foo::Foo(const Foo&)'
forFoo{ f };
Which compiler is correct?
回答1:
Ms VC ++ has a very old well-known bug. From the C++ Standard
[ Note: This two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided. —end note ]
来源:https://stackoverflow.com/questions/20589622/copy-move-elision-versus-explicitly-deleted-copy-move-constructors