I need to write a copy constructor that also transfer the ownership of a unique_ptr member of the object being copied. The situation is as follows:
class C{
// C class stuff
};
class A{
public:
public A();
public A(const A& a);
private:
std::unique_ptr<C> c_;
}
class B{
public:
B(const A& b) : a_(a){}
private:
A a_;
};
How should I implement the copy constructor for A?
Your intent or approach is wrong, I guess.
The copy-constructor is meant to create a copy of the argument, but since unique_ptr maintains sole ownership one cannot make a copy of it. You could in fact make the unique_ptr member mutable and then move the resource it points to in the copy-constructor but that would be absolutely insane (this is what std::auto_ptr does and this is why it's deprecated).
Therefore either you need to:
add a move-constructor to A and B (+ make copy-constructor deleted)
switch from unique_ptr to shared_ptr, but only if C is actually meant to be shared
There's also a third option, which is to make a copy of the object pointed to by the unique_ptr in A's copy-constructor, i.e.:
A::A(const A& a) : c_(std::unique_ptr<C>(a.c_ ? new C(*a.c_) : nullptr)) {
}
Obviously you cannot just do an assignment of std::unique_ptrs as their assignment operator is deleted. This is intentional to force the programmer to define the behavior he wants.
The new item takes ownership of c_, invalidating the original item.
The new item makes a copy of c_, retaining the original items validity.
The new item shares ownership of c_ so that both the new and original items reference the same object.
In case 1 what you're looking for is a move constructor, and the default move constructor will work fine. So you don't need to write any code, you can just do:
A temp;
A foo(std::move(temp));
Note that temp is invalid after it is moved.
In case 2 you'll need to add a custom copy constructor to A to create a copy of the original's c_:
A(const A& a):c_(new C(*(a.c_))){}
After defining this in A you can do:
A foo(A());
Note that this depends upon C's copy constructor being functional.
In case 3 you'll need to fundamentally change A from using a std::unique_ptr to using a std::shared_ptr, so the definition of c_ would become:
std::shared_ptr<C> c_;
Your construction of c_ would be identical to what you're already using for the std::unique_ptr version of c_. So just using the default implementations you could do:
A foo;
A bar(foo);
And now foo and bar point to the same C object, and share ownership of it. This shared object will not be deleted until all shared_ptrs referencing it have been deleted.
Technically, to
” write a copy constructor that also transfer the ownership of a unique_ptr member of the object being copied
you can just do this:
class Bad
{
private:
unique_ptr<int> p_;
public:
Bad(): p_( new int(666) ) {}
Bad( Bad& other )
: p_( move( other.p_ ) )
{}
};
Because a copy constructor can have also this signature, plus two more, in addition to the more conventional Bad( const Bad& ).
I named that class Bad because it's really bad, it just does not make sense to do this thing except as sabotage of someone else's code.
Instead of a copy constructor that doesn't copy,
implement a move constructor that moves, or
implement an ordinary copy constructor that copies, or
change the class design to e.g. shared ownership.
Related
I am using the pimpl idiom with a const std::unique_ptr to hold the class implementation. My class needs to support copy construction and copy assignement. What I'd like to do is manually call the copy constructor of the impl class inside the unique_ptr. However, I fail to see how.
#include <memory>
struct potato {
potato();
~potato();
potato(const potato& p);
private:
struct impl;
const std::unique_ptr<impl> _pimpl;
};
struct potato::impl {
int carbs = 42;
};
potato::potato()
: _pimpl(std::make_unique<impl>()) {
}
potato::~potato() = default;
potato::potato(const potato& p) {
// Try to call the copy constructor of impl, stored in unique_ptr, not the
// unique_ptr copy-constructor (which doesn't exist).
_pimpl.get()->impl(p._pimpl); // This doesn't work.
}
I've checked out another question about explicitly calling the copy-constructor on an object. One answer recommended using placement new.
Object dstObject;
new(&dstObject) Object(&anotherObject);
Could I use this in my copy-constructor? If so, how? I don't really understand whats happening there. Thank you.
What I'd like to do is manually call the copy constructor of the impl class inside the unique_ptr
Here lies your error. As you are inside the (copy) constructor of potato, there's no impl object already constructed over which you'd have to "manually" invoke the copy constructor.
Just construct your new impl passing to it a reference to the original impl to copy.
potato::potato(const potato& p)
: _pimpl(std::make_unique<impl>(*p._pimpl) {
}
As for assignment, you can easily forward to the impl assignment operator:
potato &operator=(const potato &p) {
*_pimpl = *p._pimpl;
return *this;
}
You can invoke constructors explicitly on uninitialized storage with the placement new operator, as you mentioned. You can return the storage of an object to an uninitialized state by explicitly calling its destructor.
Here’s a simple implementation of the assignment operator that explicitly invokes the copy constructor and the destructor you already defined as part of your interface:
#include <new>
potato& potato::operator=(const potato& x)
{
if ( this != &x ) { // check for self-assignment!
this->~potato();
new(this) potato(x);
}
return *this;
}
You would probably also want to define a move constructor and overload the assignment operator when the right-hand side is a temporary. That is, overload for potato&& src as well as const potato& src. You could use the swap idiom if your class supports it, or the same code as above, but calling new(this) potato(std::move(src));.
If you have access to the destructor and copy constructor of the class wrapped in a smart pointer, you can do the same trick with them, just dereferencing the smart pointers. You probably don’t want to, though.
The default copy constructor and assignment operator ought to work just fine, if the contents of the class are smart pointers, STL containers, and so on. You probably would want to copy the data referenced by the smart pointers by writing things like *p = x or *p = *q or std::swap, rather than explicit calls to the copy constructor.
I often find myself using unique pointers in C++ when I want polymorphic behaviour. I typically implement pure abstract classes something like the below:
class A {
public:
virtual A* clone() const = 0; // returns a pointer to a deep copy of A
// other methods go here
};
The clone method comes in handy when I want to embellish another class with its own instance of A, for example:
#include <memory>
class B {
private:
std::unique_ptr<A> a_ptr;
public:
// ctor
B(const A& a) {
a_ptr = std::unique_ptr<A>(a.clone());
//...
}
// copy ctor
B(const B& other) : B(*other.a_ptr) {}
};
I invariably end up implementing the copy constructor in B to avoid a compiler error (MSVC gives a vague message about attempting to reference a deleted function), which makes complete sense because of the unique pointer. My questions can be summarised as follows:
Do I actually need the copy constructor in B? Perhaps there's a better pattern that would allow me to avoid it altogether.
If yes to 1, can I stop there? Will I ever need to implement the other default functions? I.e. is there any scenario where I need a default constructor and destructor also?
In practice, whenever I feel I need to implement the default functions, I typically implement a move-constructor alongside the other three; I usually use the copy-and-swap-idiom (as per GManNickG's answer in this thread). I assume this wouldn't change anything, but maybe I am wrong!
Thanks a lot!
First, I think the signature of your clone function could be
virtual std::unique_ptr<A> clone() = 0;
as you want deep copies of A instances and exclusive ownership within B. Second, you indeed have to define a copy constructor for your class when you want it to be copyable. Same for an assignment operator. This is due to the fact that std::unique_ptr is a move-only type, which hinders the compiler to generate default implementations.
Other special member functions are not needed, though they might make sense. The compiler won't generate move constructor and move assignment operator for you (as you ship your own copy/assignment functions), though in your case, you can = default; them easily. The destructor can equally well be defined with = default;, which would be in line with the core guidelines.
Note that defining the destructor via = default should be done in a translation unit, as std::unique_ptr requires the full type do be known upon freeing its resource.
Whether you need a default constructor totally depends on how yo want to use the class B.
As #lubgr mentioned in his answer, You should return unique_ptr not a raw one from the clone function. Anyway, going to Your questions:
Do You need a copy constructor in B? Well it depends on Your use cases, but if You copy objects of class B You may need one. But as You said, You do it quite often, so it would be wise to consider more generic approach. One of these would be creating a wrapper for unique_ptr which would have copy constructor and which would make a deep copy of this pointer in this copy constructor.
Consider following example:
template<class T>
class unique_ptr_wrap {
public:
unique_ptr_wrap(std::unique_ptr< T > _ptr) : m_ptr(std::move(_ptr)){}
unique_ptr_wrap(const unique_ptr_wrap &_wrap){
m_ptr = _wrap->clone();
}
unique_ptr_wrap(unique_ptr_wrap &&_wrap){
m_ptr = std::move(_wrap.m_ptr);
}
T *operator->() const {
return m_ptr.get();
}
T &operator*() const {
return *m_ptr;
}
private:
std::unique_ptr< T > m_ptr;
};
This again depends on Your needs. I personally would recommend overloading move constructor as well, to make it use less dynamic allocations (but this may be premateure optimization which is root of all evil).
As i know, when we assign one object is another default copy constructor will be called.
class class1 obj1;
class class2 obj2;
obj1(obj2); //default copy constructor will be called by compiler
So, when should I write explicitly the copy constructor?
In your case the copy-assignment operator will be called, not the copy-constructor. To call the copy-constructor you would have do to e.g.
class1 obj1;
class1 obj2 = obj1; // Invokes the copy-constructor in obj2
A good idea when to write a copy-constructor (or a copy-assignment operator, or a destructor) you can see by reading about the rule of three. In short, if you have any of a destructor, copy-constructor or copy-assignment operator, then you should probably have all of them.
Also, while the compiler will auto-generate copy-constructor and copy-assignment operator for you if you do not provide your own, you have to remember that those auto-generated function will only do a shallow copy. If you have e.g. pointers to memory you allocate in the object, the auto-generated functions will only copy the actual pointer, and not what it points to. This means that after a copy you have two objects both pointing to the same memory. If you delete the pointer in the destructor, and one of the objects are destructed, the other object will still have its pointer, but it will now point to deleted memory.
You will get a default copy constructor when you don't write one, provided you don't add any of the three or five to your class : destructor, copy or move assignment or constructor.
Sometimes this does the right thing. For example, if you just need a shallow copy, or if the member's corresponding functions fo the right thing, for example smart pointers.
If an object exist prior to the assign, then it does not involve a construction but the assignment operator, signatures are:
T& operator=( T const & ); // from l-value ref
T& operator=( T && ); // from r-value ref, since c++11
A frequent strategy is to write the assignment operator as the idiom "copy and swap" :
T& operator=( T const & o ) {
T val( o ); // you need to write the copy ctor
swap(*this,o); // you need to write the swap
return *this;
}
T& operator=( T && o ) {
T val( std::move(o) ); // you need to write the move ctor
swap(*this,o); // you need to write the swap
return *this;
}
The c++11 version of that strategy
T& operator=( T o ) noexcept { // copy done before the operator that can be noexcept ( swap have to too)
swap(*this,o); // you need to write the swap
return *this;
}
In some cases you will find that the way your objects should be copied is not trivial.
If you consider the class :
class Car {
string BrandName;
int NumberOfPassenger;
}
Then it is clear that when you'll be copying two objects, you'll simply want to copy them member by member. There's nothing special to do here so the defaut copy constructor will work just fine.
But imagine that the class is instead :
class Car {
string BrandName;
int NumberOfPassenger;
Mechanics EngineeringStuff;
}
Here Mechanics is a reference type. What the copy constructor will do is simply copying the reference to the new object, so both cars - car1 and car2 - will share the same EngineeringStuff. But a more natural behaviour would be to allocate manually a new Mechanics object when performing the copy, so the cars don't share the same wheels, motors etc...
More generally, it's usually when you have to deal with reference types or certain kind of business logic that you will need to explicitly write your copy constructor.
I was reading C++11 Faq and came across this code. I have a better understanding of C++ coding, but I'm still not able to understand the below code.
template<class T>
class Handle {
T* p;
public:
Handle(T* pp) : p{pp} {}
~Handle() { delete p; } // user-defined destructor: no implicit copy or move
Handle(Handle&& h) :p{h.p} { h.p=nullptr; }; // transfer ownership
Handle& operator=(Handle&& h) { delete p; p=h.p; h.p=nullptr; return *this; } // transfer ownership
Handle(const Handle&) = delete; // no copy
Handle& operator=(const Handle&) = delete;
// ...
};
What does "transfer ownership" mean?
Why is the copy ctor equated to "delete"? how is it useful?
Please if someone can add a few examples with explanation, it would be a great help.
It's a move constructor, the special && syntax introduced in C++11 takes a rvalue reference, so a reference to a variable which has no name and can't be referenced anywhere else inside the code.
What happens in the constructor is that the Handle takes the ownership of the Handle passed through the move constructor in the way that it steals (pass me the term) the T* p inside by assigning its value to its own variable and then setting nullptr to the variable of the rvalue passed.
This is used because you don't really need to copy an rvalue, since that value won't be used anymore in the code, so it's safe to just take its data, this avoids a, possibly costly, copy constructor.
In C++ you had copy constructors and copy operators, which were expensive if your object was big. Now in C++11 you have move constructor and move operator which says "take everything from the source and kill it".
mybigthing y ;
...
mybigthing x( move(y)) ;
y is created with lots of stuff internally. after x(y), y is now empty and all the big stuff is in x.
One of the main reasons for this is to make returning big objects from functions free:
mybigthing f()
{
mybigthing tmp ;
...
return tmp ;
}
{
mybigthing y= f() ;
}
In c++03, this would be horrible performance wise. Now its free. The compilers are required to actually use y as the temporary inside of f() and never do any copies.
transfer ownership means if you do a=b the contents of b belong to a and does not exist in b anymore. This makes more sense in the example {A a; dosomething(a); return a;}. a exist locally in the function. It's contents are being moved into the return value. If A is a typedef for std::string it would mean the string internals have been moved instead of making a copy of a intentionally long string (html page maybe). However I believe string has a copy on write flag so it wouldn't make a copy in that situation but other classes may not bother to implement a copy on write.
The reason the constructor and assignment operator (which are move, not copy) delete is because the current p may be pointing to something. Not freeing it means a memory leak.
about your second question:
Why is the copy ctor equated to "delete"? how is it useful?
Here is an answer:
http://www.developerfusion.com/article/133063/constructors-in-c11/
C++11 Explicitly Deleted Constructors
C++11 also supports the concept of explicitly deleted constructors.
For example, you can define a class for which you do not want to write
any constructors and you also do not want the compiler to generate the
default constructor. In that case you need to explicitly delete the
default constructor:
class MyClass { public:
MyClass() = delete; };
I have this problem, there is a function foo() as follows,
vector<ClassA> vec;
void foo()
{
ClassA a; //inside foo, a ClassA object will be created
a._ptr = new char[10];
vec.push_back(a); //and this newly created ClassA object should be put into vec for later use
}
And AFAIK, vec will invoke ClassA's copy-ctor to make a copy of the newly created object a, and here is the problem. If I define ClassA's copy-ctor the usual way,
ClassA::ClassA(const ClassA &ra) : _ptr(0)
{
_ptr = ra._ptr;
}
then object a and its copy (created by vec) will have pointers _ptr pointing to the same area, when foo finishes, a will call the destructor to release _ptr, then a's copy in vec will be a dangling pointer, right? Due to this problem, I want to implement ClassA's copy-ctor this way,
ClassA::ClassA(ClassA &ra) : _ptr(0) //take non-const reference as parameter
{
std::swap(_ptr, a._ptr);
}
Is my implementation ok? Or any other way can help accomplish the job?
To answer your titular question: Yes, any constructor for a class T that has one mandatory argument of type T & or T const & (it may also have further, defaulted arguments) is a copy constructor. In C++11, there's also a move constructor which requires one argument of type T &&.
Having a non-constant copy constructor that actually mutates the argument gives your class very unusual semantics (usually "transfer semantics") and should be extensively documented; it also prevents you from copying something constant (obviously). The old std::auto_ptr<T> does exactly that.
If at all possible, the new C++11-style mutable rvalue references and move constructors provide a far better solution for the problem of "moving" resources around when they're no longer needed in the original object. This is because an rvalue reference is a reference to a mutable object, but it can only bind to "safe" expressions such as temporaries or things that you have explicitly cast (via std::move) and thus marked as disposable.
C++11 introduced move constructors for this exact purpose:
ClassA::ClassA(ClassA&& ra)
: _ptr(ra._ptr)
{
ra._ptr = nullptr;
}
Alternatively you can declare _ptr to be a shared pointer:
std::shared_ptr<char[]> _ptr;
and then default denerated copy constructor will do just fine.
You should not copy the pointer, you should copy the context that the pointer is pointing to. You should also initialize the class by telling it how many elements you want, instead of allocating it by accessing a public pointer.
Since you want to copy the object, not move it, you should allocate resources in the new object when copying.
class A {
int* p_;
int size_;
public:
A(int size)
: p_(new int[size]()),
size_(size) {
}
A(const A &a)
: p_(new int[a.size_]),
size_(a.size_) {
std::copy(a.p_, a.p_ + a.size_, p_);
}
...
};
int main () {
A a(10);
vec.push_back(a);
}
However, if you know that the object you will copy isn't used after it's copied, you could move it's resources instead.
The problem with your implementation is that you will not be able to pass temporary objects as arguments for this copy-ctor (temporaries are always const). Like already mentioned the best solution would be to move to c++11 and use move semantics. If it is not possible shared_array can be an alternative.
Additional comment:
Avoid these kind of problems creating the object with new and storing pointers to the object in the vector.