Jump to content
  • Advertisement
Sign in to follow this  
Lode

copying classes

This topic is 4831 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Say I have class A and class B. Class A has NO custom copy contructor or assignement operator defined. B HAS a custom copy constructor and assignement operator defined. Class A contains an object of class B in it. Now I do:
A x, y = {some parameters};


x = y; //remember that A had no custom assignement operator
Will the object of type B inside A, be copied bit by bit (so pointers are not updated if necessary), or will the custom assignement operator of B be called (B has one after all as I mentioned above)? In other words, if class A itself does not need a deep copy, but class B does need a deep copy and has it defined, and class A contains a class B in it, will the default shallow copy of A call B's deep copy, or not? Also, because I don't want to type the same thing twice, if the code of the copy constructor and assignement operator are exactly the same, is there a way to have to type it only once?

Share this post


Link to post
Share on other sites
Advertisement
B's copy constructor will be called. The default copy operation isn't a bitwise copy but a memberwise copy.

In other words, if all your members either are basic type or have their own copy constructor (destructor, assignment operator), the enclosing class doesn't need you to define a copy constructor (destructor, assignment operator).

Quote:
Also, because I don't want to type the same thing twice, if the code of the copy constructor and assignement operator are exactly the same, is there a way to have to type it only once?


Yes and no... The safest way is to implement the assignment operator as a copy construction of a temporary and a swap with the target variable. You will, of course, have to implement the swap function... probably in terms of other member swaps.

Share this post


Link to post
Share on other sites
Quote:
Original post by Fruny
Yes and no... The safest way is to implement the assignment operator as a copy construction of a temporary and a swap with the target variable. You will, of course, have to implement the swap function... probably in terms of other member swaps.


Do you think it could be possible to call the assignement operator from the copy constructor (if I type somthing like "this = the_other_one" in the copy constructor and define the operator= function)?

Share this post


Link to post
Share on other sites
I believe Fruny ment something like this:

#include <algorithm>

class MyClass
{
public:
MyClass(const MyClass & rhs) {/*Copy constructor's code*/}

MyClass & operator=(const MyClass & rhs)
{
MyClass temp(rhs); //Create a copy
std::swap(classMemberVariables, temp.classMemberVariables); //Swap the variables
return *this;
}
};


The reason to create a temp is to prevent problems with self-assigments if resources have to be freed, e.g.

MyClass instance;
//Later on in the function
MyClass & anotherInstance = instance;
//Further down
instance = anotherInstance;

Pretend that your class contains a pointer, what happens if you did this?

MyClass & operator=(const MyClass & rhs)
{
this->myPointer = rhs.myPointer;
rhs.myPointer = 0; //Oh dear, rhs == *this!! We've creater a memory leak
return *this;
}

Hope that helps

Share this post


Link to post
Share on other sites
desertcube, I've always just compared the other object to myself, is there a reason why you would prefer the swap approach to this?? It seems like a neat approach but if you assigning to your self should be disallowed I think the

if ( rhs !== this ) approach is more clear.

Cheers
Chris

Share this post


Link to post
Share on other sites
Quote:
Original post by chollida1
desertcube, I've always just compared the other object to myself, is there a reason why you would prefer the swap approach to this?? It seems like a neat approach but if you assigning to your self should be disallowed I think the

if ( rhs !== this ) approach is more clear.

Cheers
Chris

I'm not entirely sure in all honestly!! I read it somewhere and thought it was smart!

A quick google gave me this, which basically says that using a swap function makes sure that the assignment will be safe from exceptions (well, it will be uneffected if an exception occurs.) Hopefully, this should make it a but clearer:

class MyClass
{
public:
MyClass() {itsPointer = new int[8];}
~MyClass() {delete [] itsPointer;}

MyClass(const MyClass & rhs);
MyClass & operator=(const MyClass & rhs);

//Functions
private:
int * itsPointer;
};

MyClass::MyClass(const MyClass & rhs)
{
itsPointer = new int[8]; //This may throw if there isn't enough memory!
std::copy(&rhs.itsPointer[0], &rhs.itsPointer[7], itsPointer); //Copy over the values
}
MyClass & MyClass::operator=(const MyClass & rhs)
{
//This statement may throw if the copy constructor fails,
//but if it does, our class will be unaffected, as we haven't changed anything!
MyClass temp(rhs);
//If you have a lot of member variables, then you'd probably create a seperate swap function.
std::swap(itsPointer, temp.itsPointer);
return *this; //Allow chaining
//As temp goes out of scope, its destructor will get called,
//but since it's pointer is now our old pointer, that peice of memory will get freed instead!
}



Share this post


Link to post
Share on other sites
Quote:
Original post by chollida1
desertcube, I've always just compared the other object to myself, is there a reason why you would prefer the swap approach to this?? It seems like a neat approach but if you assigning to your self should be disallowed I think the

if ( rhs !== this ) approach is more clear.


If your code relies upon checking for self assignment then it cannot be made exception safe. See GotW #23: Any copy assignment that "must" check for self-assignment is not exception-safe.

Checking for self assignment is a useful optimisation, however. But it shouldn't be necessary for the correct running of the code.

The original question comes up a lot as people are trying to avoid writing the same code twice (or copying and pasting). Swap is a useful member function to have on any class and makes it easy to implement the assignment operator in terms of the copy constructor and the swap function.


class MyClass {
int memberA;
double memberB;
std::vector<double> memberC;

public:
MyClass() : memberA(4), memberB(17.5), memberC(20, 1.55) {}
void swap(MyClass& other) {
std::swap(memberA, other.memberA);
std::swap(memberB, other.memberB);
memberC.swap(other);//vector has its own swap member; more efficient than calling std::swap
}
MyClass(const MyClass & rhs) {
memberA = rhs.memberA;
memberB = rhs.memberB;
memberC = rhs.memberC;
}
MyClass& operator=(const MyClass& rhs) {
MyClass temp(rhs);
temp.swap(*this);
return *this;
}
};

Share this post


Link to post
Share on other sites
petewood, shouldn't your copy constructor be implemented using the initialiser list rather then an assignment list?


MyClass(const MyClass & rhs) {
memberA = rhs.memberA;
memberB = rhs.memberB;
memberC = rhs.memberC;
}
// what if any of these variables are const? assignment will fail

// safer (and more efficient too)
MyClass(const MyClass & rhs)
: memberA(rhs.memberA)
, memberB(rhs.memberB)
, memberC(rhs.memberC)
{
}



fundamentally, I'd say that assignment and copy construction are two different things, even if they happen to contain similar code. I also fail to see the benefit in moving the work from the = operator to a swap function. There shouldn't be that much code repition anyway (i.e. if your class has 50 members, it's time to look at your class design!)

I'd disagree with that gotw article that copy construction should be implemented using an overloaded assignment op (or private copy function), as again, they are not the same thing. While it's initally fine if your class has POD's, if you add a UDT member that does something funny in it's copy/assignment you're in tonnes of trouble.

Share this post


Link to post
Share on other sites
Quote:
Original post by Fruny
B's copy constructor will be called. The default copy operation isn't a bitwise copy but a memberwise copy.

In other words, if all your members either are basic type or have their own copy constructor (destructor, assignment operator), the enclosing class doesn't need you to define a copy constructor (destructor, assignment operator).


This is one more reason to use std::string, BTW: it removes one source of pointer members from your object, thus increasing the chance that you will be able to escape from the Tyranny of the Rule of Three. :)

Quote:

Quote:
Also, because I don't want to type the same thing twice, if the code of the copy constructor and assignement operator are exactly the same, is there a way to have to type it only once?


Yes and no... The safest way is to implement the assignment operator as a copy construction of a temporary and a swap with the target variable. You will, of course, have to implement the swap function... probably in terms of other member swaps.


Is std::swap not good enough in general? Won't that do a memberwise swap? o_O

Share this post


Link to post
Share on other sites
Quote:
Original post by ChaosEngine
petewood, shouldn't your copy constructor be implemented using the initialiser list rather then an assignment list?

Shh, you're making me look bad.

(c:

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!