By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,330 Members | 1,443 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,330 IT Pros & Developers. It's quick & easy.

Copy constructor and =

P: n/a
Hello.
If I have classes that allocates dynamic memory, it is a good thing to have
a copy constructor(CC). If I have a CC, now I'm only trying to understand
when I also need to overload the assignment operator. When do I need that?
Jul 19 '05 #1
Share this Question
Share on Google+
14 Replies


P: n/a

"Gandalf" <ga*****@gunix.dk> wrote in message
news:wd*******************@newsb.telia.net...
Hello.
If I have classes that allocates dynamic memory, it is a good thing to have a copy constructor(CC). If I have a CC, now I'm only trying to understand
when I also need to overload the assignment operator. When do I need that?


Always. Your class cannot be used safely if you don't. Writing operator= is
easy if you have written a copy ctor

X& X::operator=(const X& rhs)
{
X tmp(rhs); // copy rhs to tmp
swap(tmp); // swap tmp and this
return *this; // destroy tmp
}

swap is another member function which swaps two objects. Its usually also
very easy to write, all you do is swap each member variable in your class.
E.g. assuming X has member variables a, b and c

#include <algorithm>

void X::swap(X& rhs)
{
std::swap(a, rhs.a);
std::swap(b, rhs.b);
std::swap(c, rhs.c);
}

Include <algorithm> to get the std::swap function.

john
Jul 19 '05 #2

P: n/a
"Gandalf" <ga*****@gunix.dk> wrote in message
news:wd*******************@newsb.telia.net...
Hello.
If I have classes that allocates dynamic memory, it is a good thing to have a copy constructor(CC). If I have a CC, now I'm only trying to understand
when I also need to overload the assignment operator. When do I need that?

Remember the Law of the Big Three:

"If your class needs a copy ctor, an operator=, or a virtual dtor, it
probably needs all three."

--
- John Dibling
Jul 19 '05 #3

P: n/a

"John Dibling" <di*@dibling.com> wrote in message news:T6********************@newssrv26.news.prodigy .com...
"Gandalf" <ga*****@gunix.dk> wrote in message
news:wd*******************@newsb.telia.net...
Hello.
If I have classes that allocates dynamic memory, it is a good thing to

have
a copy constructor(CC). If I have a CC, now I'm only trying to understand
when I also need to overload the assignment operator. When do I need that?

Remember the Law of the Big Three:

"If your class needs a copy ctor, an operator=, or a virtual dtor, it
probably needs all three."


The above "law" should not contain the word "virtual" prior to destructor.
Jul 19 '05 #4

P: n/a
John Harrison wrote:
Writing operator= is easy
if you have written a copy ctor

X& X::operator=(const X& rhs) {
X tmp(rhs); // copy rhs to tmp
swap(tmp); // swap tmp and this
return *this; // destroy tmp
}

swap is another member function which swaps two objects.
It's usually also very easy to write.
All you do is swap each member variable in your class.
E.g. assuming X has member variables a, b and c

#include <algorithm>

void X::swap(X& rhs) {
std::swap(a, rhs.a);
std::swap(b, rhs.b);
std::swap(c, rhs.c);
}

Include <algorithm> to get the std::swap function.


class X {
private:
size_t N;
double* A;
public:
size_t size(void) const { return N; }
const
double& operator[](size_t j) const {
return A[j]; }
X& operator=(const X&);
X(const X&);
};

Define operator= first:

X& X::operator=(const X& rhs) {
for (size_t j = 0; j < N; ++j)
A[j] = rhs[j];
return *this;
}

then the copy constructor:

X::X(const X& rhs): N(rhs.size()), A(new double[N]) {
operator=(rhs);
}

Jul 19 '05 #5

P: n/a
"E. Robert Tisdale" <E.**************@jpl.nasa.gov> schrieb im Newsbeitrag news:3F**************@jpl.nasa.gov...
: class X {
: private:
: size_t N;
: double* A;
: public:
: size_t size(void) const { return N; }
: const
: double& operator[](size_t j) const {
: return A[j]; }
: X& operator=(const X&);
: X(const X&);
: };
:
: Define operator= first:
:
: X& X::operator=(const X& rhs) {
: for (size_t j = 0; j < N; ++j)
: A[j] = rhs[j];
: return *this;
: }

This only works if N==rhs.N

: then the copy constructor:
:
: X::X(const X& rhs): N(rhs.size()), A(new double[N]) {
: operator=(rhs);
: }

In this case it might work, but remember that member variables are initialized/constructed in the order they appear in the class definition, which may be different from that of the initializers in the constructor's definition. It is also a waste of time to (default-) construct an object only to be able to use an assignment operator.

The best way to implement copy-c'tor and assignment is not implementing them at all. Using copy-constructable and assignable data members is less error prone then using raw pointers.

Heinz
Jul 19 '05 #6

P: n/a
E. Robert Tisdale wrote:
John Harrison wrote:
Writing operator= is easy
if you have written a copy ctor

X& X::operator=(const X& rhs) {
X tmp(rhs); // copy rhs to tmp
swap(tmp); // swap tmp and this
return *this; // destroy tmp
}

swap is another member function which swaps two objects.
It's usually also very easy to write.
All you do is swap each member variable in your class.
E.g. assuming X has member variables a, b and c

#include <algorithm>

void X::swap(X& rhs) {
std::swap(a, rhs.a);
std::swap(b, rhs.b);
std::swap(c, rhs.c);
}

Include <algorithm> to get the std::swap function.


class X {
private:
size_t N;
double* A;
public:
size_t size(void) const { return N; }
const
double& operator[](size_t j) const {
return A[j]; }
X& operator=(const X&);
X(const X&);
};

Define operator= first:

X& X::operator=(const X& rhs) {
for (size_t j = 0; j < N; ++j)
A[j] = rhs[j];
return *this;
}

then the copy constructor:

X::X(const X& rhs): N(rhs.size()), A(new double[N]) {
operator=(rhs);
}


Sometimes, one can also see the opposite, using the copy constructor
(through placement new) to implement operator=:

#include <new>
X& X::operator=(const X& rhs)
{
this->~X();
new(this) X(rhs);
return *this;
}

Jul 19 '05 #7

P: n/a


"Gandalf" <ga*****@gunix.dk> wrote in message
news:wd*******************@newsb.telia.net...
Hello.
If I have classes that allocates dynamic memory, it is a good thing to

have
a copy constructor(CC). If I have a CC, now I'm only trying to understand
when I also need to overload the assignment operator. When do I need
that?


Always. Your class cannot be used safely if you don't. Writing operator=
is easy if you have written a copy ctor

Is there an example when things go wrong, due to not having a operator=
defined for the class?
Jul 19 '05 #8

P: n/a

"Gandalf" <ga*****@gunix.dk> wrote in message
news:E%*******************@newsc.telia.net...


"Gandalf" <ga*****@gunix.dk> wrote in message
news:wd*******************@newsb.telia.net...
Hello.
If I have classes that allocates dynamic memory, it is a good thing to

have
a copy constructor(CC). If I have a CC, now I'm only trying to understand when I also need to overload the assignment operator. When do I need
that?


Always. Your class cannot be used safely if you don't. Writing operator=
is easy if you have written a copy ctor

Is there an example when things go wrong, due to not having a operator=
defined for the class?


Yes anytime you use operator=

class X
{
public:
X() : ptr(new int) { *ptr = 0; }
X(const& X rhs) : ptr(new int) { *ptr = *rhs.ptr; }
~X() { delete ptr; }
private:
int* ptr;
};

int main()
{
X a;
X b;
a = b;
}

After a = b, a.ptr will equal b.ptr. Then the destructors for a and b are
called, so a.ptr and b.ptr will be deleted but because they are the same
pointer, the same pointer will be deleted twice. Most likely your program
will crash.

Perhaps you think that a = b is not legal because you don't have operator=
for your class? That is not true, because if you don't define an operator=
the compiler will define one for you, same as for the copy constructor. But
when you have pointers and dynamic memory in a class the compiler defined
operator= is usually inadequate, that is why you should define your own.

john
Jul 19 '05 #9

P: n/a

"Gandalf" <ga*****@gunix.dk> wrote in message
news:Wd*******************@newsb.telia.net...
Yes anytime you use operator=

class X
{
public:
X() : ptr(new int) { *ptr = 0; }
X(const& X rhs) : ptr(new int) { *ptr = *rhs.ptr; }
~X() { delete ptr; }
private:
int* ptr;
};

int main()
{
X a;
X b;
a = b;
}

After a = b, a.ptr will equal b.ptr. Then the destructors for a and b are called, so a.ptr and b.ptr will be deleted but because they are the same
pointer, the same pointer will be deleted twice. Most likely your program will crash.
Perhaps you think that a = b is not legal because you don't have operator= for your class? That is not true, because if you don't define an operator= the compiler will define one for you, same as for the copy constructor.
But when you have pointers and dynamic memory in a class the compiler
defined operator= is usually inadequate, that is why you should define
your own.

But now I'm confused, Why is a and b pointing to the same thing after the
assignment? I thought that the copyconstructor was called when there were
no operator=, and to my best knowledge, I thought that it could handle the
pointers correctly.
SO the compilers operator= is just a silly, "make exact copy, bit by

bit". In that case I get it. Thanks.


Not quite right. The compilers operator= is to make a memberwise copy, not a
bitwise copy. So if class X has members a, b, c, which have types A, B, C
then the compiler generated X::operator= will call A::operator=,
B::operator= and C::operator=. Of course for built in types (including
pointers) operator= is a bitwise copy.

The important point about this is that if all the members of your class have
a good operator= defined then you don't have to define one yourself. If the
rule was a bitwise copy then virtually every class would need to define
operator= even if all the members of that class had a perfectly good
operator=.

These memberwise copy rules apply equally to copy constructors.

john
Jul 19 '05 #10

P: n/a

"E. Robert Tisdale" <E.**************@jpl.nasa.gov> wrote in message
news:3F**************@jpl.nasa.gov...
John Harrison wrote:
E. Robert Tisdale wrote:
John Harrison wrote:
Bit of a problem if rhs.N != N.

Of course.
But any discussion of exception handling here
is a digression which could only obfuscate the point.
I'm afraid I'm obfuscated already.
What point were you making with your bugged code?


You are confused.


Clearly.
There was no bug in my code.

Your class appeared to have no constructor other than a copy constructor.

Your assignment operator appeared not to deal correctly with the situation
where the objects were of different sizes. Though in mitagation it could be
said that it was impossible to construct such objects given the code you
quoted.

To me that seems bugged, but please explain. Maybe you mised out some code
that you thought wasn't relevant, or maybe I just don't understand.
Unlike your example, my example addresses the case
which concerned Gandalf -- classes that allocate dynamic memory.


My code intended was not to show exception safety, it was intended to show
that writing an assignment operator was easy once a copy constructor had
been written, which seemed to be the OP's situation.

john
Jul 19 '05 #11

P: n/a

"E. Robert Tisdale" <E.**************@jpl.nasa.gov> wrote in message
news:3F**************@jpl.nasa.gov...
John Harrison wrote:
E. Robert Tisdale wrote:
John Harrison wrote:
Bit of a problem if rhs.N != N.

Of course.
But any discussion of exception handling here
is a digression which could only obfuscate the point.


I'm afraid I'm obfuscated already.
What point were you making with your bugged code?


You are confused.
There was no bug in my code.


I still don't understand the point of your code and you still haven't
explained. Bugged or not, what is the point of defining a copy constructor
in terms of an assignment operator? You seem to think it preferable (as far
as I can tell) but I think you should explain why.

john
Jul 19 '05 #12

P: n/a
John Harrison wrote:
E. Robert Tisdale wrote:
John Harrison wrote:
E. Robert Tisdale wrote:

John Harrison wrote:

>Bit of a problem if rhs.N != N.

Of course.
But any discussion of exception handling here
is a digression which could only obfuscate the point.

I'm afraid I'm obfuscated already.
What point were you making with your bugged code?


You are confused.
There was no bug in my code.


I still don't understand the point of your code and you still haven't
explained. Bugged or not, what is the point of defining a copy constructor
in terms of an assignment operator? You seem to think it preferable (as far
as I can tell) but I think you should explain why.


Unlike your example, my example addresses the case
which concerned Gandalf -- classes that allocate dynamic memory.

In this case, it is better to define operator= first
then use it to define the copy constructor.

Jul 19 '05 #13

P: n/a
> >
I still don't understand the point of your code and you still haven't
explained. Bugged or not, what is the point of defining a copy constructor in terms of an assignment operator? You seem to think it preferable (as far as I can tell) but I think you should explain why.


Unlike your example, my example addresses the case
which concerned Gandalf -- classes that allocate dynamic memory.

In this case, it is better to define operator= first
then use it to define the copy constructor.


Why?

john
Jul 19 '05 #14

P: n/a

"E. Robert Tisdale" <E.**************@jpl.nasa.gov> wrote in message news:3F**************@jpl.nasa.gov...

X& X::operator=(const X& rhs) {
for (size_t j = 0; j < N; ++j)
A[j] = rhs[j];
return *this;
}


What happens when the assigned to value has a smaller value for
N than the right hand side?
Jul 19 '05 #15

This discussion thread is closed

Replies have been disabled for this discussion.