I have an uncopiable class. Copying this would be problematic. I want to guarantee that it won't be ever copied, so I made its copy constructor deleted
:
class A { public: A(); A(const A&) = delete; }; A fun() { return A(); }; int main() { A a = fun(); };
Unfortunately, g++ won't compile this on the reason:
t.cc: In function ‘A fun()’: t.cc:8:12: error: use of deleted function ‘A::A(const A&)’ return A(); ^ t.cc:4:5: note: declared here A(const A&) = delete; ^ t.cc: In function ‘int main()’: t.cc:12:13: error: use of deleted function ‘A::A(const A&)’ A a = fun(); ^ t.cc:4:5: note: declared here A(const A&) = delete; ^
But this is a very clear situation where copy elision should be used, so the copy constructor shouldn't be ever called. Why is it so?
The reason the copy constructor is not called is because the copy constructor itself is a function with one parameter. You didn't call such function,so it didn't execute.
The copy constructor and copy-assignment operator are public but deleted. It is a compile-time error to define or call a deleted function. The intent is clear to anyone who understands =default and =delete . You don't have to understand the rules for automatic generation of special member functions.
A copy constructor cannot receive value by call by value method. While we invoke copy constructor an object of same class must be passed to it. But the object passed need to be copied in formal arguments. Values of one object is copied in another by copy constructor.
It is necessary to pass object as reference and not by value because if you pass it by value its copy is constructed using the copy constructor. This means the copy constructor would call itself to make copy. This process will go on until the compiler runs out of memory.
Until C++17 copy elision is an optimization the compiler is not required to do, so classes must be copyable since the compiler might want to copy (even if it actually does not). In C++17 copy elision will be guaranteed in many cases and then classes won't need copy ctors.
See also:
http://en.cppreference.com/w/cpp/language/copy_elision
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0135r0.html
https://herbsutter.com/2016/06/30/trip-report-summer-iso-c-standards-meeting-oulu/ (the bit about "Guaranteed copy elision")
You could perhaps use the old trick of declaring the copy constructor in your class but not actually implement it? That should please the compiler as long as it does not actually invoke the copy ctor. I didn't test that, but I believe it should work for your case until C++17 arrives.
You can't force copy elision (yet) (see other answers).
However, you can provide a default move constructor for your class, this will move (and thus, not copy) the return value if RVO/NRVO is not possible. To do this you should add = default
for your move constructors:
class A { public: A() = default; A(const A&) = delete; A(A&&) = default; A& operator=(A&&) = default; };
Example
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With