Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is a copy constructor required when returning by implicit conversion?

Tags:

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 &);         ^ 
like image 712
user541686 Avatar asked Jun 16 '14 07:06

user541686


People also ask

Is copy constructor necessary?

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).

What is copy constructor when it is used implicitly for what purpose?

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.

Does return by value call copy constructor?

The copy constructor is called because you call by value not by reference.

When copy constructor is implicitly called?

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.


2 Answers

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.

like image 60
Angew is no longer proud of SO Avatar answered Sep 23 '22 13:09

Angew is no longer proud of SO


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.

like image 27
Luchian Grigore Avatar answered Sep 23 '22 13:09

Luchian Grigore