I am looking for a good example of how to implement a derived and a base class with move semantics. The more I have thought about it, the more it seems that the default move constructor and assignment move operator will normally do the job because most standard (STL) types and smart pointers are default moveable.
Anyway, in the case we have a class hierarchy, which requires an explicit move implementation, how should I do it - at least as a first cut?
In this example, I am using a raw pointer which I would normally wrap in a std::unique_ptr but I needed an example of something to move which is not default moveable.
Any help would be much appreciated. :)
Currently, I have made the following attempt:
struct BlobA
{
char data[0xaa];
};
struct BlobB
{
char data[0xbb];
};
//----------------------------------------
class Base
{
public:
//Default construct the Base class
//C++11 allows the data members to initialised, where declared. Otherwise you would do it here.
Base()
{
}
//Define the destructor as virtual to ensure that the derived destructor gets called. (In case it is necessary. It's not in this example but still good practice.)
virtual ~Base()
{
delete m_moveableDataInBase; //this is a contrived example to show non-default moveable data, in practice RAII should be used rather than deletes like this
}
//Copy constructor, needs to accept a const ref to another Base class with which it copies the data members
Base(const Base& other) :
m_moveableDataInBase(new BlobA(*other.m_moveableDataInBase)), // copy the other's moveable data
m_pNonMoveableDataInBase(other.m_pNonMoveableDataInBase) // copy the other's non-moveable data
{
}
//Assignment operator uses the canonical copy then swap idiom. It returns a reference to allow chaining: a = b = c
//This is thus implemented in terms of the copy constructor.
Base& operator=(const Base& rhs)
{
Base temp(rhs);
Swap(temp);
return *this;
}
//The move construtor is declared as throwing no exceptions so that it will be called by STL algorithms
//It accepts an rvalue and moves the Base part.
Base(Base&& other) noexcept :
m_moveableDataInBase(nullptr) // don't bother allocating our own resources to moveable data because we are about to move (steal) the other's resource
{
Swap(other);
}
//The move assignment operator is declared as throwing no exceptions so that it will be called by STL algorithms
//It accepts an rvalue and moves (steals) the data resources from the rhs using swap and copies the non moveable data from the rhs
Base& operator=(Base&& rhs) noexcept
{
//move (steal) the moveable contents from rhs
std::swap(m_moveableDataInBase, rhs.m_moveableDataInBase);
//copy the non-moveable contents from rhs
m_pNonMoveableDataInBase = rhs.m_pNonMoveableDataInBase;
return *this;
}
private:
//this private member swaps the data members' contents.
//It is private because it isn't virtual and only swaps the base contents and is thus not safe as a public interface
void Swap(Base& other)
{
std::swap(m_moveableDataInBase, other.m_moveableDataInBase);
std::swap(m_pNonMoveableDataInBase, other.m_pNonMoveableDataInBase);
}
//an example of some large blob of data which we would like to move instead of copy for performance reasons.
//normally, I would have used a unique_ptr but this is default moveable and I need an example of something that isn't
BlobA* m_moveableDataInBase{ new BlobA };
//an example of some data that we can't or don't want to move
int m_pNonMoveableDataInBase = 123;
};
//----------------------------------------
class Derived : public Base
{
public:
//Default construct the Derived class, this is called after the base class constructor
//C++11 allows the data members to initialised, where declared. Otherwise you would do it here.
Derived()
{
}
//Default virtual destructor, to clean up stuff that can't be done automatically through RAII
virtual ~Derived()
{
delete m_pMoveableDataInDerived; //this is a contrived example to show non-default moveable data, in practice RAII should be used rather than deletes like this
}
//Copy constructor, needs to accept a const ref to another derived class with which it
//first copy constructs the base and then copies the derived data members
Derived(const Derived& other) :
Base(other), // forward to the base copy constructor
m_pMoveableDataInDerived(new BlobB(*other.m_pMoveableDataInDerived)), // copy the other's moveable data
m_pNonMoveableDataInDerived(other.m_pNonMoveableDataInDerived) // copy the other's non-moveable data
{
}
//Assignment operator uses the canonical copy then swap idiom. It returns a reference to allow chaining: a = b = c
//Because it uses the derived copy constructor, which in turn copy constructs the base, we don't forward to the base assignment operator.
Derived& operator=(const Derived& rhs)
{
Derived temp(rhs);
Swap(temp);
return *this;
}
//The move construtor is declared as throwing no eceptions so that it will be called by STL algorithms
//It accepts an rvalue and first moves the Base part and then the Derived part.
//There is no point in allocating any resource before moving so in this example, m_pBlobB is set to nullptr
Derived(Derived&& other) noexcept
: Base(std::move(other)), // forward to base move constructor
m_pMoveableDataInDerived(nullptr) // don't bother allocating our own resources to moveable data because we are about to move (steal) the other's resource
{
Swap(other);
}
//The move assignment operator is declared as throwing no exceptions so that it will be called by STL algorithms
//It accepts an rvalue and first calls the base assignment operator and then moves the data resources from the rhs using swap
Derived& operator=(Derived&& rhs) noexcept
{
//forward to the base move operator=
Base::operator=(std::move(rhs));
//move (steal) the moveable contents from rhs
std::swap(m_pMoveableDataInDerived, rhs.m_pMoveableDataInDerived);
//copy the non-moveable contents from rhs
m_pNonMoveableDataInDerived = rhs.m_pNonMoveableDataInDerived;
}
private:
//this member swaps the Derived data members contents.
//It is private because it doesn't swap the base contents and is thus not safe as a public interface
void Swap(Derived& other) noexcept
{
std::swap(m_pMoveableDataInDerived, other.m_pMoveableDataInDerived);
std::swap(m_pNonMoveableDataInDerived, other.m_pNonMoveableDataInDerived);
}
//an example of some large blob of data which we would like to move instead of copy for performance reasons.
//normally, I would have used a unique_ptr but this is default moveable and I need an example of something that isn't
BlobB* m_pMoveableDataInDerived{ new BlobB };
//an example of some data that we can't or don't want to move
int m_pNonMoveableDataInDerived = 456;
};
You have to start out knowing what your class invariants are. A class invariant is something or some relationship that is always true among your data members. And then you want to make sure that your special members can operate with any value which satisfies your class invariants. Special members should not have preconditions (except that all class invariants must be true).
Let's take your example as an example case to discuss. First lets just concentrate on Base. I like to put my private data members up front so that they are close to the special members. This way I can more easily see what defaulted or implicitly declared special members actually do.
Base
class Base
{
//an example of some large blob of data which we would like to move
// instead of copy for performance reasons.
//normally, I would have used a unique_ptr but this is default moveable
// and I need an example of something that isn't
BlobA* m_moveableDataInBase{ new BlobA };
//an example of some data that we can't or don't want to move
int m_pNonMoveableDataInBase = 123;
So far so good, but there is a slight ambiguity here: Can m_moveableDataInBase == nullptr? There is no one right or wrong answer. This is a question that the author of Base must answer, and then write code to enforce.
Also, outline your member functions. Even if you decide you want to inline them, do so outside the declaration. Otherwise your class declaration becomes difficult to read:
class Base
{
BlobA* m_moveableDataInBase{ new BlobA };
int m_pNonMoveableDataInBase = 123;
public:
virtual ~Base();
Base() = default;
Base(const Base& other);
Base& operator=(const Base& rhs);
Base(Base&& other) noexcept;
Base& operator=(Base&& rhs) noexcept;
};
The destructor is the most telling special member. I like to get it declared/defined first:
Base::~Base()
{
delete m_moveableDataInBase;
}
This looks good. But this does not yet answer the question as to whether m_moveableDataInBase can be nullptr. Next, if it exists, the default constructor. Prefer = default definitions when practical.
Now the copy constructor:
Base::Base(const Base& other)
: m_moveableDataInBase(new BlobA(*other.m_moveableDataInBase))
, m_pNonMoveableDataInBase(other.m_pNonMoveableDataInBase)
{
}
Ok, this says something significant:
other.m_moveableDataInBase != nullptr // ever
I glanced ahead and looked at your move constructor, and that leaves the moved-from value with m_moveableDataInBase == nullptr. So we have a problem:
Either there is a bug in your copy constructor, and you should check for the case other.m_moveableDataInBase == nullptr, or
There is a bug in your move constructor and it should not leave the moved-from state with m_moveableDataInBase == nullptr.
Neither solution is the correct one. The Base author has to make this design decision. If he choses 2, there really is no reasonable way to implement the move constructor such that it is any faster than the copy constructor. In that case the thing to do is not write a move constructor and just let the copy constructor do the job. So I'll choose 1 so that there is still a move constructor to talk about. Corrected copy constructor:
Base::Base(const Base& other)
: m_moveableDataInBase(other.m_moveableDataInBase ?
new BlobA(*other.m_moveableDataInBase) :
nullptr)
, m_pNonMoveableDataInBase(other.m_pNonMoveableDataInBase)
{
}
Also, since we chose this invariant, it might not be a bad idea to revisit the default constructor and instead say:
BlobA* m_moveableDataInBase = nullptr;
Now we have a noexcept default constructor.
Next comes the copy assignment operator. Do not fall into the trap of selecting the copy/swap idiom by default. Sometimes this idiom is fine. But it is often poorly performing. And performance is more important than code reuse. Consider this alternative to copy/swap:
Base&
Base::operator=(const Base& rhs)
{
if (this != &rhs)
{
if (m_moveableDataInBase == nullptr)
{
if (rhs.m_moveableDataInBase != nullptr)
m_moveableDataInBase = new BlobA(*rhs.m_moveableDataInBase);
}
else // m_moveableDataInBase != nullptr
{
if (rhs.m_moveableDataInBase != nullptr)
*m_moveableDataInBase = *rhs.m_moveableDataInBase;
else
{
delete m_moveableDataInBase;
m_moveableDataInBase = nullptr;
}
}
m_pNonMoveableDataInBase = rhs.m_pNonMoveableDataInBase;
}
return *this;
}
If it is common for values of Base to have m_moveableDataInBase != nullptr, then this rewrite is significantly faster than copy/swap. In this common case, copy/swap always does 1 new and 1 delete. This version does 0 news and 0 deletes. It just copies 170 bytes.
And if we had chosen the design where it is an invariant that m_moveableDataInBase != nullptr, then the copy assignment gets even simpler:
Base&
Base::operator=(const Base& rhs)
{
*m_moveableDataInBase = *rhs.m_moveableDataInBase;
m_pNonMoveableDataInBase = rhs.m_pNonMoveableDataInBase;
return *this;
}
Minimizing calls to the heap is not premature optimization. It is engineering. It is what move semantics is made out of. This is precisely why std::vector and std::string copy assignment do not use the copy/swap idiom. It would be too slow.
Move constructor: I would code it like this:
Base::Base(Base&& other) noexcept
: m_moveableDataInBase(std::move(other.m_moveableDataInBase))
, m_pNonMoveableDataInBase(std::move(other.m_pNonMoveableDataInBase))
{
other.m_moveableDataInBase = nullptr;
}
This saves a few loads and stores. I didn't bother inspecting the generated assembly. I urge you to do so before choosing your implementation over this one. In a noexcept move constructor, count loads and stores.
As a style-guide, I like to move the members even when I know they are scalars and the move has no impact. This saves the reader of the code from having to ensure that all non-moved members are scalars.
Your move assignment looks fine to me:
Base&
Base::operator=(Base&& rhs) noexcept
{
//move (steal) the moveable contents from rhs
std::swap(m_moveableDataInBase, rhs.m_moveableDataInBase);
//copy the non-moveable contents from rhs
m_pNonMoveableDataInBase = rhs.m_pNonMoveableDataInBase;
return *this;
}
The one time when you don't want to do this is when you have non-memory resources on the lhs that need to be destructed immediately, as opposed to swapped to the rhs. But your example is only swapping memory.
Derived
For Derived I would write it exactly as I've shown for Base, except for first copying/moving the Base exactly as you show in your code. For example here is the move constructor:
Derived::Derived(Derived&& other) noexcept
: Base(std::move(other))
, m_pMoveableDataInDerived(std::move(other.m_pMoveableDataInDerived))
, m_pNonMoveableDataInDerived(std::move(other.m_pNonMoveableDataInDerived))
{
other.m_pMoveableDataInDerived = nullptr;
}
Also tag ~Dervied() with override instead of virtual. You want the compiler to tell you if you've accidentally somehow not overridden ~Base() with ~Derived().
class Derived : public Base
{
BlobB* m_pMoveableDataInDerived = nullptr;
int m_pNonMoveableDataInDerived = 456;
public:
~Derived() override;
Derived() = default;
Derived(const Derived& other);
Derived& operator=(const Derived& rhs);
Derived(Derived&& other) noexcept;
Derived& operator=(Derived&& rhs) noexcept;
};
Test
Also test all six special members (whether you have them or not) with static_assert and type-traits:
static_assert(std::is_nothrow_destructible<Base>{}, "");
static_assert(std::is_nothrow_default_constructible<Base>{}, "");
static_assert(std::is_copy_constructible<Base>{}, "");
static_assert(std::is_copy_assignable<Base>{}, "");
static_assert(std::is_nothrow_move_constructible<Base>{}, "");
static_assert(std::is_nothrow_move_assignable<Base>{}, "");
static_assert(std::is_nothrow_destructible<Derived>{}, "");
static_assert(std::is_nothrow_default_constructible<Derived>{}, "");
static_assert(std::is_copy_constructible<Derived>{}, "");
static_assert(std::is_copy_assignable<Derived>{}, "");
static_assert(std::is_nothrow_move_constructible<Derived>{}, "");
static_assert(std::is_nothrow_move_assignable<Derived>{}, "");
You can even test these for your Blob types:
static_assert(std::is_trivially_destructible<BlobA>{}, "");
static_assert(std::is_trivially_default_constructible<BlobA>{}, "");
static_assert(std::is_trivially_copy_constructible<BlobA>{}, "");
static_assert(std::is_trivially_copy_assignable<BlobA>{}, "");
static_assert(std::is_trivially_move_constructible<BlobA>{}, "");
static_assert(std::is_trivially_move_assignable<BlobA>{}, "");
static_assert(std::is_trivially_destructible<BlobB>{}, "");
static_assert(std::is_trivially_default_constructible<BlobB>{}, "");
static_assert(std::is_trivially_copy_constructible<BlobB>{}, "");
static_assert(std::is_trivially_copy_assignable<BlobB>{}, "");
static_assert(std::is_trivially_move_constructible<BlobB>{}, "");
static_assert(std::is_trivially_move_assignable<BlobB>{}, "");
Summary
In summary, give each of the six special members all the loving care they deserve, even if the result is to inhibit them, implicitly declare them, or explicitly default or delete them. The complier-generated move members will move each base, then move each non-static data member. Prefer that recipe, default it when you can, and simply augment it when it is necessary.
Highlight your class API by moving member function definitions out of the class declaration.
Test. At the very least test that you do or do not have all 6 special members, and if you have them, if they are noexcept or trivial (or not).
Use copy/swap with caution. It can be a performance killer.
Anyway, in the case we have a class hierarchy, which requires an
explicit move implementation, how should I do it - at least as a first
cut?
Don't.
You don't move the base class. You move the pointer to the base class. For the derived class, you can move it but then you know what the derived class is so you can just write the move constructor/assignment operator accordingly.
Also, raw pointers are completely movable. How do you think unique_ptr is implemented?
I would ditch the "swap with other" approach which doesn't help with the readablity and go with simple assignments instead.
class A{
int * dataA;
public:
A() { dataA = new int(); }
virtual ~A() {delete dataA; }
A(A&& rhs) noexcept { dataA = rhs.dataA; rhs.dataA = nullptr; }
A& operator = (A&& rhs) noexcept {
if (this != &rhs){
if (dataA) delete dataA;
dataA = rhs.dataA;
rhs.dataA = nullptr;
}
return *this;
}
}
class B: public A{
int* dataB;
public:
B(){ dataB = new int(); }
virtual ~B() {delete dataB; }
B(B&& rhs) noexcept : A(std::move(rhs)) { dataB = rhs.dataB; rhs.dataB = nullptr; }
B& operator = (B&& rhs) noexcept {
A::operator == (std::move(rhs));
if (this != &rhs){
if (dataB) delete dataB;
dataB = rhs.dataB;
rhs.dataB = nullptr;
}
return *this;
}
}
call the parent move constructor to move the parent-part of the object. do the rest in the move constructor.
the same goes for the assignment operator.
Related
How do I implement a copy constructor for a class that has a unique_ptr member variable? I am only considering C++11.
Since the unique_ptr can not be shared, you need to either deep-copy its content or convert the unique_ptr to a shared_ptr.
class A
{
std::unique_ptr< int > up_;
public:
A( int i ) : up_( new int( i ) ) {}
A( const A& a ) : up_( new int( *a.up_ ) ) {}
};
int main()
{
A a( 42 );
A b = a;
}
You can, as NPE mentioned, use a move-ctor instead of a copy-ctor but that would result in different semantics of your class. A move-ctor would need to make the member as moveable explicitly via std::move:
A( A&& a ) : up_( std::move( a.up_ ) ) {}
Having a complete set of the necessary operators also leads to
A& operator=( const A& a )
{
up_.reset( new int( *a.up_ ) );
return *this,
}
A& operator=( A&& a )
{
up_ = std::move( a.up_ );
return *this,
}
If you want to use your class in a std::vector, you basically have to decide if the vector shall be the unique owner of an object, in which case it would be sufficient to make the class moveable, but not copyable. If you leave out the copy-ctor and copy-assignment, the compiler will guide your way on how to use a std::vector with move-only types.
The usual case for one to have a unique_ptr in a class is to be able to use inheritance (otherwise a plain object would often do as well, see RAII). For this case, there is no appropriate answer in this thread up to now.
So, here is the starting point:
struct Base
{
//some stuff
};
struct Derived : public Base
{
//some stuff
};
struct Foo
{
std::unique_ptr<Base> ptr; //points to Derived or some other derived class
};
... and the goal is, as said, to make Foo copiable.
For this, one needs to do a deep copy of the contained pointer to ensure the derived class is copied correctly.
This can be accomplished by adding the following code:
struct Base
{
//some stuff
auto clone() const { return std::unique_ptr<Base>(clone_impl()); }
protected:
virtual Base* clone_impl() const = 0;
};
struct Derived : public Base
{
//some stuff
protected:
virtual Derived* clone_impl() const override { return new Derived(*this); };
};
struct Foo
{
std::unique_ptr<Base> ptr; //points to Derived or some other derived class
//rule of five
~Foo() = default;
Foo(Foo const& other) : ptr(other.ptr->clone()) {}
Foo(Foo && other) = default;
Foo& operator=(Foo const& other) { ptr = other.ptr->clone(); return *this; }
Foo& operator=(Foo && other) = default;
};
There are basically two things going on here:
The first is the addition of a user-defined copy constructor of Foo, This is necessary, as the unique_ptr-member iself has no copy constructor. In the declared copy-constructor, a new unique_ptr is created, and the pointer is set to a copy of the original pointee.
In case inheritance is involved, the copy of the original pointee must be done carefully. The reason is that doing a simple copy via std::unique_ptr<Base>(*ptr) in the code above would result in slicing, i.e., only the base component of the object gets copied, while the derived part is missing.
To avoid this, the copy has to be done via the clone-pattern. The
idea is to do the copy through a virtual function clone_impl()
which returns a Base* in the base class. In the derived class,
however, it is extended via covariance to return a Derived*, and
this pointer points to a newly created copy of the derived class. The
base class can then access this new object via the base class pointer
Base*, wrap it into a unique_ptr, and return it via the actual
clone() function which is called from the outside.
Second, by declaring a user-defined copy-constructor as done above, the move constructor gets deleted by the corresponding C++ language rules. The declaration via Foo(Foo &&) = default is thus just to let the compiler know that the standard move constructor still applies.
Try this helper to create deep copies, and cope when the source unique_ptr is null.
template< class T >
std::unique_ptr<T> copy_unique(const std::unique_ptr<T>& source)
{
return source ? std::make_unique<T>(*source) : nullptr;
}
Eg:
class My
{
My( const My& rhs )
: member( copy_unique(rhs.member) )
{
}
// ... other methods
private:
std::unique_ptr<SomeType> member;
};
Daniel Frey mention about copy solution,I would talk about how to move the unique_ptr
#include <memory>
class A
{
public:
A() : a_(new int(33)) {}
A(A &&data) : a_(std::move(data.a_))
{
}
A& operator=(A &&data)
{
a_ = std::move(data.a_);
return *this;
}
private:
std::unique_ptr<int> a_;
};
They are called move constructor and move assignment
you could use them like this
int main()
{
A a;
A b(std::move(a)); //this will call move constructor, transfer the resource of a to b
A c;
a = std::move(c); //this will call move assignment, transfer the resource of c to a
}
You need to wrap a and c by std::move because they have a name
std::move is telling the compiler to transform the value to
rvalue reference whatever the parameters are
In technical sense, std::move is analogy to something like "std::rvalue"
After moving, the resource of the unique_ptr is transfer to another unique_ptr
There are many topics that document rvalue reference; this is a pretty easy one to begin with.
Edit :
The moved object shall remain valid but unspecified state.
C++ primer 5, ch13 also give a very good explanation about how to "move" the object
I suggest use make_unique
class A
{
std::unique_ptr< int > up_;
public:
A( int i ) : up_(std::make_unique<int>(i)) {}
A( const A& a ) : up_(std::make_unique<int>(*a.up_)) {};
int main()
{
A a( 42 );
A b = a;
}
unique_ptr is not copyable, it is only moveable.
This will directly affect Test, which is, in your second, example also only moveable and not copyable.
In fact, it is good that you use unique_ptr which protects you from a big mistake.
For example, the main issue with your first code is that the pointer is never deleted which is really, really bad. Say, you would fix this by:
class Test
{
int* ptr; // writing this in one line is meh, not sure if even standard C++
Test() : ptr(new int(10)) {}
~Test() {delete ptr;}
};
int main()
{
Test o;
Test t = o;
}
This is also bad. What happens, if you copy Test? There will be two classes that have a pointer that points to the same address.
When one Test is destroyed, it will also destroy the pointer. When your second Test is destroyed, it will try to remove the memory behind the pointer, as well. But it has already been deleted and we will get some bad memory access runtime error (or undefined behavior if we are unlucky).
So, the right way is to either implement copy constructor and copy assignment operator, so that the behavior is clear and we can create a copy.
unique_ptr is way ahead of us here. It has the semantic meaning: "I am unique, so you cannot just copy me." So, it prevents us from the mistake of now implementing the operators at hand.
You can define copy constructor and copy assignment operator for special behavior and your code will work. But you are, rightfully so (!), forced to do that.
The moral of the story: always use unique_ptr in these kind of situations.
I have a class B with a set of constructors and an assignment operator.
Here it is:
class B
{
public:
B();
B(const string& s);
B(const B& b) { (*this) = b; }
B& operator=(const B & b);
private:
virtual void foo();
// and other private member variables and functions
};
I want to create an inheriting class D that will just override the function foo(), and no other change is required.
But, I want D to have the same set of constructors, including copy constructor and assignment operator as B:
D(const D& d) { (*this) = d; }
D& operator=(const D& d);
Do I have to rewrite all of them in D, or is there a way to use B's constructors and operator? I would especially want to avoid rewriting the assignment operator because it has to access all of B's private member variables.
You can explicitly call constructors and assignment operators:
class Base {
//...
public:
Base(const Base&) { /*...*/ }
Base& operator=(const Base&) { /*...*/ }
};
class Derived : public Base
{
int additional_;
public:
Derived(const Derived& d)
: Base(d) // dispatch to base copy constructor
, additional_(d.additional_)
{
}
Derived& operator=(const Derived& d)
{
Base::operator=(d);
additional_ = d.additional_;
return *this;
}
};
The interesting thing is that this works even if you didn't explicitly define these functions (it then uses the compiler generated functions).
class ImplicitBase {
int value_;
// No operator=() defined
};
class Derived : public ImplicitBase {
const char* name_;
public:
Derived& operator=(const Derived& d)
{
ImplicitBase::operator=(d); // Call compiler generated operator=
name_ = strdup(d.name_);
return *this;
}
};
Short Answer: Yes you will need to repeat the work in D
Long answer:
If your derived class 'D' contains no new member variables then the default versions (generated by the compiler should work just fine). The default Copy constructor will call the parent copy constructor and the default assignment operator will call the parent assignment operator.
But if your class 'D' contains resources then you will need to do some work.
I find your copy constructor a bit strange:
B(const B& b){(*this) = b;}
D(const D& d){(*this) = d;}
Normally copy constructors chain so that they are copy constructed from the base up. Here because you are calling the assignment operator the copy constructor must call the default constructor to default initialize the object from the bottom up first. Then you go down again using the assignment operator. This seems rather inefficient.
Now if you do an assignment you are copying from the bottom up (or top down) but it seems hard for you to do that and provide a strong exception guarantee. If at any point a resource fails to copy and you throw an exception the object will be in an indeterminate state (which is a bad thing).
Normally I have seen it done the other way around.
The assignment operator is defined in terms of the copy constructor and swap. This is because it makes it easier to provide the strong exception guarantee. I don't think you will be able to provide the strong guarantee by doing it this way around (I could be wrong).
class X
{
// If your class has no resources then use the default version.
// Dynamically allocated memory is a resource.
// If any members have a constructor that throws then you will need to
// write your owen version of these to make it exception safe.
X(X const& copy)
// Do most of the work here in the initializer list
{ /* Do some Work Here */}
X& operator=(X const& copy)
{
X tmp(copy); // All resource all allocation happens here.
// If this fails the copy will throw an exception
// and 'this' object is unaffected by the exception.
swap(tmp);
return *this;
}
// swap is usually trivial to implement
// and you should easily be able to provide the no-throw guarantee.
void swap(X& s) throws()
{
/* Swap all members */
}
};
Even if you derive a class D from from X this does not affect this pattern.
Admittedly you need to repeat a bit of the work by making explicit calls into the base class, but this is relatively trivial.
class D: public X
{
// Note:
// If D contains no members and only a new version of foo()
// Then the default version of these will work fine.
D(D const& copy)
:X(copy) // Chain X's copy constructor
// Do most of D's work here in the initializer list
{ /* More here */}
D& operator=(D const& copy)
{
D tmp(copy); // All resource all allocation happens here.
// If this fails the copy will throw an exception
// and 'this' object is unaffected by the exception.
swap(tmp);
return *this;
}
// swap is usually trivial to implement
// and you should easily be able to provide the no-throw guarantee.
void swap(D& s) throws()
{
X::swap(s); // swap the base class members
/* Swap all D members */
}
};
You most likely have a flaw in your design (hint: slicing, entity semantics vs value semantics). Having a full copy/value semantics on an object from a polymorphic hierarchy is often not a need at all. If you want to provide it just in case one may need it later, it means you'll never need it. Make the base class non copyable instead (by inheriting from boost::noncopyable for instance), and that's all.
The only correct solutions when such need really appears are the envelop-letter idiom, or the little framework from the article on Regular Objects by Sean Parent and Alexander Stepanov IIRC. All the other solutions will give you trouble with slicing, and/or the LSP.
On the subject, see also C++CoreReference C.67: C.67: A base class should suppress copying, and provide a virtual clone instead if "copying" is desired.
You will have to redefine all constructors that are not default or copy constructors. You do not need to redefine the copy constructor nor assignment operator as those provided by the compiler (according to the standard) will call all the base's versions:
struct base
{
base() { std::cout << "base()" << std::endl; }
base( base const & ) { std::cout << "base(base const &)" << std::endl; }
base& operator=( base const & ) { std::cout << "base::=" << std::endl; }
};
struct derived : public base
{
// compiler will generate:
// derived() : base() {}
// derived( derived const & d ) : base( d ) {}
// derived& operator=( derived const & rhs ) {
// base::operator=( rhs );
// return *this;
// }
};
int main()
{
derived d1; // will printout base()
derived d2 = d1; // will printout base(base const &)
d2 = d1; // will printout base::=
}
Note that, as sbi noted, if you define any constructor the compiler will not generate the default constructor for you and that includes the copy constructor.
The original code is wrong:
class B
{
public:
B(const B& b){(*this) = b;} // copy constructor in function of the copy assignment
B& operator= (const B& b); // copy assignment
private:
// private member variables and functions
};
In general, you can not define the copy constructor in terms of the copy assignment, because the copy assignment must release the resources and the copy constructor don't !!!
To understand this, consider:
class B
{
public:
B(Other& ot) : ot_p(new Other(ot)) {}
B(const B& b) {ot_p = new Other(*b.ot_p);}
B& operator= (const B& b);
private:
Other* ot_p;
};
To avoid memory leak , the copy assignment first MUST delete the memory pointed by ot_p:
B::B& operator= (const B& b)
{
delete(ot_p); // <-- This line is the difference between copy constructor and assignment.
ot_p = new Other(*b.ot_p);
}
void f(Other& ot, B& b)
{
B b1(ot); // Here b1 is constructed requesting memory with new
b1 = b; // The internal memory used in b1.op_t MUST be deleted first !!!
}
So, copy constructor and copy assignment are different because the former construct and object into an initialized memory and, the later, MUST first release the existing memory before constructing the new object.
If you do what is originally suggested in this article:
B(const B& b){(*this) = b;} // copy constructor
you will be deleting an unexisting memory.
How do I implement a copy constructor for a class that has a unique_ptr member variable? I am only considering C++11.
Since the unique_ptr can not be shared, you need to either deep-copy its content or convert the unique_ptr to a shared_ptr.
class A
{
std::unique_ptr< int > up_;
public:
A( int i ) : up_( new int( i ) ) {}
A( const A& a ) : up_( new int( *a.up_ ) ) {}
};
int main()
{
A a( 42 );
A b = a;
}
You can, as NPE mentioned, use a move-ctor instead of a copy-ctor but that would result in different semantics of your class. A move-ctor would need to make the member as moveable explicitly via std::move:
A( A&& a ) : up_( std::move( a.up_ ) ) {}
Having a complete set of the necessary operators also leads to
A& operator=( const A& a )
{
up_.reset( new int( *a.up_ ) );
return *this,
}
A& operator=( A&& a )
{
up_ = std::move( a.up_ );
return *this,
}
If you want to use your class in a std::vector, you basically have to decide if the vector shall be the unique owner of an object, in which case it would be sufficient to make the class moveable, but not copyable. If you leave out the copy-ctor and copy-assignment, the compiler will guide your way on how to use a std::vector with move-only types.
The usual case for one to have a unique_ptr in a class is to be able to use inheritance (otherwise a plain object would often do as well, see RAII). For this case, there is no appropriate answer in this thread up to now.
So, here is the starting point:
struct Base
{
//some stuff
};
struct Derived : public Base
{
//some stuff
};
struct Foo
{
std::unique_ptr<Base> ptr; //points to Derived or some other derived class
};
... and the goal is, as said, to make Foo copiable.
For this, one needs to do a deep copy of the contained pointer to ensure the derived class is copied correctly.
This can be accomplished by adding the following code:
struct Base
{
//some stuff
auto clone() const { return std::unique_ptr<Base>(clone_impl()); }
protected:
virtual Base* clone_impl() const = 0;
};
struct Derived : public Base
{
//some stuff
protected:
virtual Derived* clone_impl() const override { return new Derived(*this); };
};
struct Foo
{
std::unique_ptr<Base> ptr; //points to Derived or some other derived class
//rule of five
~Foo() = default;
Foo(Foo const& other) : ptr(other.ptr->clone()) {}
Foo(Foo && other) = default;
Foo& operator=(Foo const& other) { ptr = other.ptr->clone(); return *this; }
Foo& operator=(Foo && other) = default;
};
There are basically two things going on here:
The first is the addition of a user-defined copy constructor of Foo, This is necessary, as the unique_ptr-member iself has no copy constructor. In the declared copy-constructor, a new unique_ptr is created, and the pointer is set to a copy of the original pointee.
In case inheritance is involved, the copy of the original pointee must be done carefully. The reason is that doing a simple copy via std::unique_ptr<Base>(*ptr) in the code above would result in slicing, i.e., only the base component of the object gets copied, while the derived part is missing.
To avoid this, the copy has to be done via the clone-pattern. The
idea is to do the copy through a virtual function clone_impl()
which returns a Base* in the base class. In the derived class,
however, it is extended via covariance to return a Derived*, and
this pointer points to a newly created copy of the derived class. The
base class can then access this new object via the base class pointer
Base*, wrap it into a unique_ptr, and return it via the actual
clone() function which is called from the outside.
Second, by declaring a user-defined copy-constructor as done above, the move constructor gets deleted by the corresponding C++ language rules. The declaration via Foo(Foo &&) = default is thus just to let the compiler know that the standard move constructor still applies.
Try this helper to create deep copies, and cope when the source unique_ptr is null.
template< class T >
std::unique_ptr<T> copy_unique(const std::unique_ptr<T>& source)
{
return source ? std::make_unique<T>(*source) : nullptr;
}
Eg:
class My
{
My( const My& rhs )
: member( copy_unique(rhs.member) )
{
}
// ... other methods
private:
std::unique_ptr<SomeType> member;
};
Daniel Frey mention about copy solution,I would talk about how to move the unique_ptr
#include <memory>
class A
{
public:
A() : a_(new int(33)) {}
A(A &&data) : a_(std::move(data.a_))
{
}
A& operator=(A &&data)
{
a_ = std::move(data.a_);
return *this;
}
private:
std::unique_ptr<int> a_;
};
They are called move constructor and move assignment
you could use them like this
int main()
{
A a;
A b(std::move(a)); //this will call move constructor, transfer the resource of a to b
A c;
a = std::move(c); //this will call move assignment, transfer the resource of c to a
}
You need to wrap a and c by std::move because they have a name
std::move is telling the compiler to transform the value to
rvalue reference whatever the parameters are
In technical sense, std::move is analogy to something like "std::rvalue"
After moving, the resource of the unique_ptr is transfer to another unique_ptr
There are many topics that document rvalue reference; this is a pretty easy one to begin with.
Edit :
The moved object shall remain valid but unspecified state.
C++ primer 5, ch13 also give a very good explanation about how to "move" the object
I suggest use make_unique
class A
{
std::unique_ptr< int > up_;
public:
A( int i ) : up_(std::make_unique<int>(i)) {}
A( const A& a ) : up_(std::make_unique<int>(*a.up_)) {};
int main()
{
A a( 42 );
A b = a;
}
unique_ptr is not copyable, it is only moveable.
This will directly affect Test, which is, in your second, example also only moveable and not copyable.
In fact, it is good that you use unique_ptr which protects you from a big mistake.
For example, the main issue with your first code is that the pointer is never deleted which is really, really bad. Say, you would fix this by:
class Test
{
int* ptr; // writing this in one line is meh, not sure if even standard C++
Test() : ptr(new int(10)) {}
~Test() {delete ptr;}
};
int main()
{
Test o;
Test t = o;
}
This is also bad. What happens, if you copy Test? There will be two classes that have a pointer that points to the same address.
When one Test is destroyed, it will also destroy the pointer. When your second Test is destroyed, it will try to remove the memory behind the pointer, as well. But it has already been deleted and we will get some bad memory access runtime error (or undefined behavior if we are unlucky).
So, the right way is to either implement copy constructor and copy assignment operator, so that the behavior is clear and we can create a copy.
unique_ptr is way ahead of us here. It has the semantic meaning: "I am unique, so you cannot just copy me." So, it prevents us from the mistake of now implementing the operators at hand.
You can define copy constructor and copy assignment operator for special behavior and your code will work. But you are, rightfully so (!), forced to do that.
The moral of the story: always use unique_ptr in these kind of situations.
I wrote a Stack and Queue implementation (Linked List based). There is one stack (bigStack). For example, I separate bigStack (example: stackA and stackB). I pop() a node from bigStack, I push() in stackA. In the same way, I push() in stackB. I want bigStack to not change. Therefore I want to clone the bigStack object. How do I clone objects in C++? Or is there another solution to my problem?
class Stack : public List {
public:
Stack() {}
Stack(const Stack& rhs) {}
Stack& operator=(const Stack& rhs) {};
~Stack() {}
int Top() {
if (head == NULL) {
cout << "Error: The stack is empty." << endl;
return -1;
} else {
return head->nosu;
}
}
void Push(int nosu, string adi, string soyadi, string bolumu) {
InsertNode(0, nosu, adi, soyadi, bolumu);
}
int Pop() {
if (head == NULL) {
cout << "Error: The stack is empty." << endl;
return -1;
} else {
int val = head->nosu;
DeleteNode(val);
return val;
}
}
void DisplayStack(void);
};
then...
Stack copyStack = veriYapilariDersi;
copyStack.DisplayStack();
The typical solution to this is to write your own function to clone an object. If you are able to provide copy constructors and copy assignement operators, this may be as far as you need to go.
class Foo
{
public:
Foo();
Foo(const Foo& rhs) { /* copy construction from rhs*/ }
Foo& operator=(const Foo& rhs) {};
};
// ...
Foo orig;
Foo copy = orig; // clones orig if implemented correctly
Sometimes it is beneficial to provide an explicit clone() method, especially for polymorphic classes.
class Interface
{
public:
virtual Interface* clone() const = 0;
};
class Foo : public Interface
{
public:
Interface* clone() const { return new Foo(*this); }
};
class Bar : public Interface
{
public:
Interface* clone() const { return new Bar(*this); }
};
Interface* my_foo = /* somehow construct either a Foo or a Bar */;
Interface* copy = my_foo->clone();
EDIT: Since Stack has no member variables, there's nothing to do in the copy constructor or copy assignment operator to initialize Stack's members from the so-called "right hand side" (rhs). However, you still need to ensure that any base classes are given the opportunity to initialize their members.
You do this by calling the base class:
Stack(const Stack& rhs)
: List(rhs) // calls copy ctor of List class
{
}
Stack& operator=(const Stack& rhs)
{
List::operator=(rhs);
return * this;
};
In C++ copying the object means cloning. There is no any special cloning in the language.
As the standard suggests, after copying you should have 2 identical copies of the same object.
There are 2 types of copying: copy constructor when you create object on a non initialized space and copy operator where you need to release the old state of the object (that is expected to be valid) before setting the new state.
If your object is not polymorphic (and a stack implementation likely isn't), then as per other answers here, what you want is the copy constructor. Please note that there are differences between copy construction and assignment in C++; if you want both behaviors (and the default versions don't fit your needs), you'll have to implement both functions.
If your object is polymorphic, then slicing can be an issue and you might need to jump through some extra hoops to do proper copying. Sometimes people use as virtual method called clone() as a helper for polymorphic copying.
Finally, note that getting copying and assignment right, if you need to replace the default versions, is actually quite difficult. It is usually better to set up your objects (via RAII) in such a way that the default versions of copy/assign do what you want them to do. I highly recommend you look at Meyer's Effective C++, especially at items 10,11,12.
I have a class B with a set of constructors and an assignment operator.
Here it is:
class B
{
public:
B();
B(const string& s);
B(const B& b) { (*this) = b; }
B& operator=(const B & b);
private:
virtual void foo();
// and other private member variables and functions
};
I want to create an inheriting class D that will just override the function foo(), and no other change is required.
But, I want D to have the same set of constructors, including copy constructor and assignment operator as B:
D(const D& d) { (*this) = d; }
D& operator=(const D& d);
Do I have to rewrite all of them in D, or is there a way to use B's constructors and operator? I would especially want to avoid rewriting the assignment operator because it has to access all of B's private member variables.
You can explicitly call constructors and assignment operators:
class Base {
//...
public:
Base(const Base&) { /*...*/ }
Base& operator=(const Base&) { /*...*/ }
};
class Derived : public Base
{
int additional_;
public:
Derived(const Derived& d)
: Base(d) // dispatch to base copy constructor
, additional_(d.additional_)
{
}
Derived& operator=(const Derived& d)
{
Base::operator=(d);
additional_ = d.additional_;
return *this;
}
};
The interesting thing is that this works even if you didn't explicitly define these functions (it then uses the compiler generated functions).
class ImplicitBase {
int value_;
// No operator=() defined
};
class Derived : public ImplicitBase {
const char* name_;
public:
Derived& operator=(const Derived& d)
{
ImplicitBase::operator=(d); // Call compiler generated operator=
name_ = strdup(d.name_);
return *this;
}
};
Short Answer: Yes you will need to repeat the work in D
Long answer:
If your derived class 'D' contains no new member variables then the default versions (generated by the compiler should work just fine). The default Copy constructor will call the parent copy constructor and the default assignment operator will call the parent assignment operator.
But if your class 'D' contains resources then you will need to do some work.
I find your copy constructor a bit strange:
B(const B& b){(*this) = b;}
D(const D& d){(*this) = d;}
Normally copy constructors chain so that they are copy constructed from the base up. Here because you are calling the assignment operator the copy constructor must call the default constructor to default initialize the object from the bottom up first. Then you go down again using the assignment operator. This seems rather inefficient.
Now if you do an assignment you are copying from the bottom up (or top down) but it seems hard for you to do that and provide a strong exception guarantee. If at any point a resource fails to copy and you throw an exception the object will be in an indeterminate state (which is a bad thing).
Normally I have seen it done the other way around.
The assignment operator is defined in terms of the copy constructor and swap. This is because it makes it easier to provide the strong exception guarantee. I don't think you will be able to provide the strong guarantee by doing it this way around (I could be wrong).
class X
{
// If your class has no resources then use the default version.
// Dynamically allocated memory is a resource.
// If any members have a constructor that throws then you will need to
// write your owen version of these to make it exception safe.
X(X const& copy)
// Do most of the work here in the initializer list
{ /* Do some Work Here */}
X& operator=(X const& copy)
{
X tmp(copy); // All resource all allocation happens here.
// If this fails the copy will throw an exception
// and 'this' object is unaffected by the exception.
swap(tmp);
return *this;
}
// swap is usually trivial to implement
// and you should easily be able to provide the no-throw guarantee.
void swap(X& s) throws()
{
/* Swap all members */
}
};
Even if you derive a class D from from X this does not affect this pattern.
Admittedly you need to repeat a bit of the work by making explicit calls into the base class, but this is relatively trivial.
class D: public X
{
// Note:
// If D contains no members and only a new version of foo()
// Then the default version of these will work fine.
D(D const& copy)
:X(copy) // Chain X's copy constructor
// Do most of D's work here in the initializer list
{ /* More here */}
D& operator=(D const& copy)
{
D tmp(copy); // All resource all allocation happens here.
// If this fails the copy will throw an exception
// and 'this' object is unaffected by the exception.
swap(tmp);
return *this;
}
// swap is usually trivial to implement
// and you should easily be able to provide the no-throw guarantee.
void swap(D& s) throws()
{
X::swap(s); // swap the base class members
/* Swap all D members */
}
};
You most likely have a flaw in your design (hint: slicing, entity semantics vs value semantics). Having a full copy/value semantics on an object from a polymorphic hierarchy is often not a need at all. If you want to provide it just in case one may need it later, it means you'll never need it. Make the base class non copyable instead (by inheriting from boost::noncopyable for instance), and that's all.
The only correct solutions when such need really appears are the envelop-letter idiom, or the little framework from the article on Regular Objects by Sean Parent and Alexander Stepanov IIRC. All the other solutions will give you trouble with slicing, and/or the LSP.
On the subject, see also C++CoreReference C.67: C.67: A base class should suppress copying, and provide a virtual clone instead if "copying" is desired.
You will have to redefine all constructors that are not default or copy constructors. You do not need to redefine the copy constructor nor assignment operator as those provided by the compiler (according to the standard) will call all the base's versions:
struct base
{
base() { std::cout << "base()" << std::endl; }
base( base const & ) { std::cout << "base(base const &)" << std::endl; }
base& operator=( base const & ) { std::cout << "base::=" << std::endl; }
};
struct derived : public base
{
// compiler will generate:
// derived() : base() {}
// derived( derived const & d ) : base( d ) {}
// derived& operator=( derived const & rhs ) {
// base::operator=( rhs );
// return *this;
// }
};
int main()
{
derived d1; // will printout base()
derived d2 = d1; // will printout base(base const &)
d2 = d1; // will printout base::=
}
Note that, as sbi noted, if you define any constructor the compiler will not generate the default constructor for you and that includes the copy constructor.
The original code is wrong:
class B
{
public:
B(const B& b){(*this) = b;} // copy constructor in function of the copy assignment
B& operator= (const B& b); // copy assignment
private:
// private member variables and functions
};
In general, you can not define the copy constructor in terms of the copy assignment, because the copy assignment must release the resources and the copy constructor don't !!!
To understand this, consider:
class B
{
public:
B(Other& ot) : ot_p(new Other(ot)) {}
B(const B& b) {ot_p = new Other(*b.ot_p);}
B& operator= (const B& b);
private:
Other* ot_p;
};
To avoid memory leak , the copy assignment first MUST delete the memory pointed by ot_p:
B::B& operator= (const B& b)
{
delete(ot_p); // <-- This line is the difference between copy constructor and assignment.
ot_p = new Other(*b.ot_p);
}
void f(Other& ot, B& b)
{
B b1(ot); // Here b1 is constructed requesting memory with new
b1 = b; // The internal memory used in b1.op_t MUST be deleted first !!!
}
So, copy constructor and copy assignment are different because the former construct and object into an initialized memory and, the later, MUST first release the existing memory before constructing the new object.
If you do what is originally suggested in this article:
B(const B& b){(*this) = b;} // copy constructor
you will be deleting an unexisting memory.