The following code compiles fine in Visual C++ 2013, but not under GCC or Clang.
Which is correct?
Is an accessible copy constructor required when returning an object via an implicit conversion?
class Noncopyable { Noncopyable(Noncopyable const &); public: Noncopyable(int = 0) { } }; Noncopyable foo() { return 0; } int main() { foo(); return 0; }
GCC:
error: 'Noncopyable::Noncopyable(const Noncopyable&)' is private Noncopyable(Noncopyable const &); ^ error: within this context Noncopyable foo() { return 0; }
Clang:
error: calling a private constructor of class 'Noncopyable' Noncopyable foo() { return 0; } ^ note: implicitly declared private here Noncopyable(Noncopyable const &); ^ warning: C++98 requires an accessible copy constructor for class 'Noncopyable' when binding a reference to a temporary; was private [-Wbind-to-temporary-copy] Noncopyable foo() { return 0; } ^ note: implicitly declared private here Noncopyable(Noncopyable const &); ^
A user-defined copy constructor is generally needed when an object owns pointers or non-shareable references, such as to a file, in which case a destructor and an assignment operator should also be written (see Rule of three).
Copy constructor is used to initialize the members of a newly created object by copying the members of an already existing object. Copy constructor takes a reference to an object of the same class as an argument.
The copy constructor is called because you call by value not by reference.
A copy constructor is a member function that initializes an object using another object of the same class. The Copy constructor is called mainly when a new object is created from an existing object, as a copy of the existing object.
When you return
an expression, a temporary object of the return type is created, initialised with that expression, and then moved (or copied, if moving is not an option), into the return value. So you need an accessible copy or move constructor.
It is however possible to initialise the return value directly, by using a braced list. So the following works:
Noncopyable foo() { return {0}; }
Similar case in live example.
12.8 Copying and moving class objects [class.copy]
1/ A class object can be copied or moved in two ways: by initialization (12.1, 8.5), including for function argument passing (5.2.2) and for function value return (6.6.3); [...]
In 6.6.3 The return statement [stmt.return]:
2/ [...] The value of the expression is implicitly converted to the return type of the function in which it appears. A return statement can involve the construction and copy or move of a temporary object (12.2) [...]
and 12.2 Temporary objects [class.temporary]:
1/ Temporaries of class type are created in various contexts: binding a reference to a prvalue (8.5.3), returning a prvalue (6.6.3), a conversion that creates a prvalue (4.1, 5.2.9, 5.2.11, 5.4), [...] Note: even if there is no call to the destructor or copy/move constructor, all the semantic restrictions, such as accessibility (Clause 11) and whether the function is deleted (8.4.3), shall be satisfied. [...]
I'd argue that GCC and clang are correct - I'd even go as far as saying that any time you return by value, the return type has to have an accessible copy or move constructor.
The logic would be that a temporary is created to convert the original type to the new type (int
to Noncopyable
), and afterwards a copy of that temporary is made to return for the function.
It's essentialy the same as:
Noncopyable foo() { return Noncopyable(0); }
Would you expect a copy to be required there? I certainly would.
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