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.
Related
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 to avoid unnecessary copying in the following scenario? Class A contains base-type pointer to big object.
class A{
BigBaseClass *ptr;
A(const BigBaseClass& ob);
~A(){delete ptr;}
};
Sometimes I will need object ob to be copied. So I implement virtual cloning:
class BigBaseClass{
virtual BigBaseClass* clone() {return new BigBaseClass(*this);}
};
class BigDerivedClass : BigBaseClass{
virtual BigDerivedClass* clone() {return new BigDerivedClass(*this);}
};
A::A(const BigBaseClass& ob):ptr(ob.clone(){}
But sometimes I will create temporary BigDerivedClass object and use it to construct class A:
A a{BigDerivedClass()};
or
BigDerivedClass f(){
BigDerivedClass b;
/*constructing object*/
return b;
}
A a{f()};
Here there is no need to copy created object and then delete it. It's possible to create this object directly in the heap and store its address in a.ptr.
But it seems unlikely to me that compiler is smart enough to implement copy elision here (or is it?). So what would you suggest to avoid such unnecessary copying?
The compiler will not elide the construction of a copy via clone(): copy elision is only allowed in very specific situations. In all cases where the compiler is allowed to do copy elision the life-times of the objects involved are entirely controlled by the compiler. The four situations are (for details see 12.8 [class.copy] paragraph 8):
Returning a local name by value.
Throwing a local object.
Copying a temporary object which isn't bound to a reference.
When catching by value.
The details when copy-elision is applicable even in these situations are somewhat non-trivial. In any case, return new T(*this); doesn't fit any of these situations.
Typical big objects don't hold their data as part of the object. Instead, they typically hold some data structures which can be moved. If you want to retain the simplicity when using A{f()} without wanting to copy the result of f(), you can get away with a move constructor calling a virtual function transferring the content instead of copying it:
#include <utility>
class BigBaseClass {
public:
virtual ~BigBaseClass() {}
virtual BigBaseClass* clone() const = 0;
virtual BigBaseClass* transfer() && = 0;
};
class A{
BigBaseClass *ptr;
public:
A(BigBaseClass&& obj): ptr(std::move(obj).transfer()) {}
A(BigBaseClass const& obj): ptr(obj.clone()) {}
~A(){delete ptr;}
};
class BigDerivedClass
: public BigBaseClass {
BigDerivedClass(BigDerivedClass const&); // copy the content
BigDerivedClass(BigDerivedClass&&); // transfer the content
BigDerivedClass* clone() const { return new BigDerivedClass(*this); }
BigDerivedClass* transfer() && { return new BigDerivedClass(std::move(*this)); }
};
BigDerivedClass f() {
return BigDerivedClass();
}
int main()
{
A a{f()};
}
Whether move construction does help copying the big objects does depend on how the objects are internally implemented. If they object essentially just contains a couple of pointers to the actual large data, move construction should avoid any relevant cost as transferring the pointers would be negligible compared to setting up the actual data. If the data is actually held within the object the transfer wouldn't really help (although it is generally a bad idea to so anyway for a variety of reasons).
class BigBaseClass
{
public:
virtual ~BigBaseClass() {}
virtual BigBaseClass* clone() const { return new BigBaseClass(*this); }
};
class BigDerivedClass : public BigBaseClass
{
public:
BigDerivedClass* clone() const override { return new BigDerivedClass(*this); }
};
class A
{
BigBaseClass *ptr;
public:
explicit A(BigBaseClass* ob);
~A() { delete ptr; }
};
A::A(BigBaseClass* ob) : ptr(ob)
{
}
int main()
{
A a(new BigDerivedClass);
}
You might think that move semantics would be a good idea, but that doesn't really work in this case since BigBaseClass is a base class, and moving a BigDerivedClass into a BigBaseClass would only move the BigBaseClass parts. But using a smart pointer would be good idea too, unless you are sure that the rest of your code is exception-free.
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.
I'm not sure if I've worded this correctly.
Basically, I have a class like this:
class A
{
public:
A()
{
CreateHandle(&m_handle);
}
~A()
{
DeleteHandle(&m_handle);
}
private:
Handle m_handle;
}
And it's a member of another class:
class B
{
public:
B(int data) : m_data(data) {}
/* ... */
private:
A m_a;
int m_data;
}
And finally I have a third class which is sort of like a container of Bs:
class C
{
public:
/* ... */
void AddOneB(B b)
{
m_bs.push_back(b);
}
private:
std::vector<B> m_bs;
}
Lastly, in my code where I'm creating a C instance, I would do something like this:
...
C cObj;
cObj.AddOneB( B(23) );
...
My problem is that the destructor of A actually destroys the memory that it created in it's constructor. So doing this results in my cObj getting a B with an A that it no good.
My first thought was to make the instance of A in B a std::shared_ptr, but I was wondering if there's any other, paradigm (is that the word), to handle situations like this?
I can't see how copy constructors or move constructors can help here because the destructor will be called regardless.
You need to make a choice: either A has unique ownership of the Handle, or it has shared ownership of it.
If the former, you need to make A noncopyable. For exactly the problems you present in your question. If C++11, you should make it movable:
A(const A&) = delete;
A& operator=(const A&) = delete;
A(A&& rhs) {
// transfer ownership of m_handle from rhs to this
// so that rhs doesn't destroy it
}
If the latter, you need to reference count the Handle so that only one of the copies of A destroys it:
class A {
int* refCnt;
Handle m_handle;
public:
A()
{
CreateHandle(&m_handle);
refCnt = new int(1);
}
A(const A& rhs)
: m_handle(rhs.m_handle)
, refCnt(rhs.refCnt)
{
(*refCnt)++; // now we have an additional reference
}
~A() {
if (--*refCnt == 0) {
// only destroy if we're the LAST one
DeleteHandle(&m_handle);
}
}
};
Shared ownership is more expensive (and what I wrote above is not thread-safe, if that's a concern), so pick the one that makes the most definitely. Definitely you cannot have a copyable type that expresses have unique ownership - that is asking for trouble.
i have a base class, 2 derived classes and an entitymanager class that has a container of base pointers pointing to derived objects. i have a virtual clone method in the base to take care of the copy constructors in the derived classes, but im having trouble wrapping my head around overloading the assignment operator and preventing slicing, could someone please help with that and perhaps review how ive handled the entitymanager copy constructor? i think its ok
class System
{
public:
virtual System* clone()=0;
};
class projectile :public System
{
public:
projectile* clone()
{
return new projectile(*this);
}
};
class player : public System
{
public:
player* clone()
{
return new player(*this);
}
};
class EntityManager
{
private:
vector<System*> theEntities;
public:
EntityManager(){}
EntityManager(EntityManager& other)
{
for (size_t i=0;i<other.theEntities.size();i++)
theEntities.push_back(other.theEntities[i]->clone());
}
void init()
{
projectile* aProjectile = new projectile;
player* aPlayer = new player;
theEntities.push_back(aProjectile);
theEntities.push_back(aPlayer);
}
};
int main (int argc, char * const argv[])
{
EntityManager originalManager;
originalManager.init();
EntityManager copyManager(originalManager);
return 0;
}
Add a swap member that swaps the containers, then implement assignment as copy and swap:
void swap(EntityManager& other)
{ theEntities.swap(other.theEntities); }
EntityManager& operator=(EntityManager other)
{ swap(other); return *this; }
The argument to the assignment operator will be copied using the copy constructor you've already written, then you swap the data, so the data that belonged to *this will be destroyed when that parameter goes out of scope, and *this owns the newly copied data.
Re-using the copy constructor in this way means you only need to implement a correct copy constructor (and correct swap, which is usually easy to get right) and your assignment operator is really simple and automatically correct.
N.B. your init member and copy ctor are not exception safe, if any push_back operation throws an exception you leak memory. You're also missing a destructor, but I assume that's present in the real code.