Reputation: 1015
I've written a simple linked list because a recent interview programming challenge showed me how rusty my C++ has gotten. On my list I declared a private copy constructor because I wanted to explicitly avoid making any copies (and of course, laziness). I ran in to some trouble when I wanted to return an object by value that owns one of my lists.
class Foo
{
MyList<int> list; // MyList has private copy constructor
public:
Foo() {};
};
class Bar
{
public:
Bar() {};
Foo getFoo()
{
return Foo();
}
};
I get a compiler error saying that MyList has a private copy constructor when I try to return a Foo object by value. Should Return-Value-Optimization negate the need for any copying? Am I required to write a copy constructor? I'd never heard of move constructors until I started looking for solutions to this problem, is that the best solution? If so, I'll have to read up on them. If not, what is the preferred way to solve this problem?
Upvotes: 1
Views: 1157
Reputation: 279235
The basic problem is that return by value might copy. The C++ implementation is not required by the standard to apply copy-elision where it does apply. That's why the object still has to be copyable: so that the implementation's decision when to use it doesn't affect whether the code is well-formed.
Anyway, it doesn't necessarily apply to every copy that the user might like it to. For example there is no elision of copy assignment.
I think your options are:
getFoo
to take a Foo&
(or maybe Foo*
) parameter, and avoid a copy by somehow mutating their object. An efficient swap
would come in handy for that. This is fairly pointless if getFoo
really returns a default-constructed Foo
as in your example, since the caller needs to construct a Foo
before they call getFoo
.Foo
wrapped in a smart pointer: either auto_ptr
or unique_ptr
. Functions defined to create an object and transfer sole ownership to their caller should not return shared_ptr
since it has no release()
function.I may have missed some.
Upvotes: 3
Reputation: 59811
The standard explicitly states that the constructor still needs to be accessible, even if it is optimized away. See 12.8/32
in a recent draft.
I prefer making an object movable and non-copyable in such situations. It makes ownership very clear and explicit.
Otherwise, your users can always use a shared_ptr
. Hiding shared ownership is at best a questionable idea (unless you can guarantee all your values are immutable).
Upvotes: 5
Reputation: 47762
The solution would be implementing your own copy constructor that would use other methods of MyList
to implement the copy semantics.
... I wanted to explicitly avoid making any copies
You have to choose. Either you can't make copies of an object, like std::istream
; then you have to hold such objects in pointers/references, since these can be copied (in C++11, you can use move semantics instead). Or you implement the copy constructor, which is probably easier then solving problems on each place a copy is needed.
Upvotes: 2