default implementation of assignment operator

G

George2

Hello everyone,


I am wondering the default implementation of assignment operator (e.g.
when we do not implement assignment operator in user defined class,
what will be returned? temporary object? reference or const reference?
deep copy or shallow copy is used in default assignment operator?)? I
have the C++ Programming Book at hand, but can not find it from Index
page.


thanks in advance,
George
 
J

Juha Nieminen

George2 said:
I am wondering the default implementation of assignment operator (e.g.
when we do not implement assignment operator in user defined class,
what will be returned? temporary object? reference or const reference?
deep copy or shallow copy is used in default assignment operator?)?

The compiler cannot automatically generate a deep-copying of the
objects because it has absolutely no way of knowing whether the member
pointers are pointing at memory allocated and owned by the object
itself, or whether they are just pointing to something else (for example
trying to deep-copy an element of a doubly-linked list would be quite a
bad idea).
The default assignment operator simply assigns each individual member
variable from the parameter to this, regardless of what it is. If it's
eg. a pointer, then a simple pointer assignment will be done.

In many cases the default assignment operator is ok, especially if the
class does not contain pointers.

It returns a const-reference to *this.
 
A

Abhishek Padmanabh

The compiler cannot automatically generate a deep-copying of the
objects because it has absolutely no way of knowing whether the member
pointers are pointing at memory allocated and owned by the object
itself, or whether they are just pointing to something else (for example
trying to deep-copy an element of a doubly-linked list would be quite a
bad idea).
The default assignment operator simply assigns each individual member
variable from the parameter to this, regardless of what it is. If it's
eg. a pointer, then a simple pointer assignment will be done.

In many cases the default assignment operator is ok, especially if the
class does not contain pointers.

It returns a const-reference to *this.

Not a const reference.
 
J

James Kanze

I am wondering the default implementation of assignment
operator (e.g. when we do not implement assignment operator
in user defined class, what will be returned? temporary
object? reference or const reference? deep copy or shallow
copy is used in default assignment operator?)? I have the C++
Programming Book at hand, but can not find it from Index page.

It does member by member assignment. Whether this does a deep
copy or a shallow one depends on the assignment operators in the
members, for raw pointers, it is shallow, since pointer
assignment is shallow.

The signature of the operator, for a class T, is usually:
T& T::eek:perator=( T const& )
If any of the base classes or members have a copy assignment
operator which requires a non-const reference, however, the
parameter will be a non-const reference.
 
J

Jim Langston

Juha said:
The compiler cannot automatically generate a deep-copying of the
objects because it has absolutely no way of knowing whether the member
pointers are pointing at memory allocated and owned by the object
itself, or whether they are just pointing to something else (for
example trying to deep-copy an element of a doubly-linked list would
be quite a bad idea).
The default assignment operator simply assigns each individual member
variable from the parameter to this, regardless of what it is. If it's
eg. a pointer, then a simple pointer assignment will be done.

In many cases the default assignment operator is ok, especially if
the class does not contain pointers.

It returns a const-reference to *this.

This behavior is sometimes refered to as a "bitwise copy" although that is
not strictly true. If it was a bitwise copy, copying the bits of the class
ignoring constructors, then there would be different values then there are.

Basically it will take the base copy of whatever types are being copied.
For most things this is fine. This will work for stl::containers,
std::string, std::vector, etc... but it usually does not give you want you
want for pointers. Your copied class will have it's pointers copied by
value, pointing to the same things they were pointing to before. In some
cases this may be what you want. In most cases it is not. One of the
biggest dangers of this behavior is when the destructor of the class
destroyes it's pointed to value (delete). Then your copied class may point
to data that is no longer valid.

Consider:

class Foo
{
public:
Foo() { MyData = new char[100]; }
~Foo() { delete[] MyData; }
private:
char* MyData;
}

If this class is copied, MyData will be copied by value, the pointer will be
copied, and you will have 2 instances pointing to the same portion of
memory, which is not what you want in most cases. Also, if the destructor
ever gets invoked, such as a temporary being created and destroyed, then
MyData will become invalid in the copied class. The normal way of dealing
with this is with a copy constructor that assigns it's own memory.

#include <algorithm>

class Foo
{
public:
Foo() { MyData = new char[100]; }
~Foo() { delete[] MyData; }
Foo( const Foo& rhs )
{
MyData = new char[100];
std::copy( &rhs.MyData[0], &rhs.MyData[99], MyData );
}
private:
char* MyData;
};
 
J

Jim Langston

Jim said:
Juha said:
The compiler cannot automatically generate a deep-copying of the
objects because it has absolutely no way of knowing whether the
member pointers are pointing at memory allocated and owned by the
object itself, or whether they are just pointing to something else
(for example trying to deep-copy an element of a doubly-linked list
would be quite a bad idea).
The default assignment operator simply assigns each individual
member variable from the parameter to this, regardless of what it
is. If it's eg. a pointer, then a simple pointer assignment will be
done. In many cases the default assignment operator is ok, especially if
the class does not contain pointers.

It returns a const-reference to *this.

This behavior is sometimes refered to as a "bitwise copy" although
that is not strictly true. If it was a bitwise copy, copying the
bits of the class ignoring constructors, then there would be
different values then there are.
Basically it will take the base copy of whatever types are being
copied. For most things this is fine. This will work for
stl::containers, std::string, std::vector, etc... but it usually does
not give you want you want for pointers. Your copied class will have
it's pointers copied by value, pointing to the same things they were
pointing to before. In some cases this may be what you want. In most
cases it is not. One of the biggest dangers of this behavior is when
the destructor of the class destroyes it's pointed to value (delete).
Then your copied class may point to data that is no longer valid.

Consider:

class Foo
{
public:
Foo() { MyData = new char[100]; }
~Foo() { delete[] MyData; }
private:
char* MyData;
}

If this class is copied, MyData will be copied by value, the pointer
will be copied, and you will have 2 instances pointing to the same
portion of memory, which is not what you want in most cases. Also,
if the destructor ever gets invoked, such as a temporary being
created and destroyed, then MyData will become invalid in the copied
class. The normal way of dealing with this is with a copy
constructor that assigns it's own memory.
#include <algorithm>

class Foo
{
public:
Foo() { MyData = new char[100]; }
~Foo() { delete[] MyData; }
Foo( const Foo& rhs )
{
MyData = new char[100];
std::copy( &rhs.MyData[0], &rhs.MyData[99], MyData );
}
private:
char* MyData;
};

A few things, this is the copy constructor, not the assignment operator.
Both would need to be specified (see the rule of three). The assignment
operator would look just about the same.
Second,
std::copy( &rhs.MyData[0], &rhs.MyData[99], MyData );
probably needs to be
std::copy( &rhs.MyData[0], &rhs.MyData[100], MyData );
because it is my understanding that the end iterator needs to point 1 past
the data.
 
P

Pete Becker

This behavior is sometimes refered to as a "bitwise copy" although that is
not strictly true. If it was a bitwise copy, copying the bits of the class
ignoring constructors, then there would be different values then there are.

That's a bit confusing, because of dangling references. So here's the
deal: the compiler-generated assignment operator does member-by-member
assignment, not bitwise assignment. Bitwise assignment copies the bits
(think memcpy). Member-by-member assignment uses each type's assignment
operator, and bitwise copying for builtin types.
 
J

Juha Nieminen

Abhishek said:
Not a const reference.

You mean it's possible, when default assignment operators are used, to
do this: (a = b) = c; ?

I think I'm pretty sure it's not, even without trying.
 
P

Pete Becker

You mean it's possible, when default assignment operators are used, to
do this: (a = b) = c; ?

I think I'm pretty sure it's not, even without trying.

Are you still sure after trying it?
 
T

Tadeusz B. Kopec

This behavior is sometimes refered to as a "bitwise copy" although that
is not strictly true. If it was a bitwise copy, copying the bits of the
class ignoring constructors, then there would be different values then
there are.

Basically it will take the base copy of whatever types are being copied.
For most things this is fine. This will work for stl::containers,
std::string, std::vector, etc... but it usually does not give you want
you want for pointers. Your copied class will have it's pointers copied
by value, pointing to the same things they were pointing to before. In
some cases this may be what you want. In most cases it is not. One of
the biggest dangers of this behavior is when the destructor of the class
destroyes it's pointed to value (delete). Then your copied class may
point to data that is no longer valid.

Well, generally if an object owns some pointers, they should be wrapped
in some std::auto_ptr, boost::scoped_ptr or something like this.
Otherwise you loose exception safety and gain many headaches. OTOH
compiler generated assignment operator for class with std::auto_ptr is
even more surprising, so I recommend const std::auto_ptr.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top