Checking assignment operators with *this pointer

J

john

Hey,

I know we use the pointer this to obtain a class object or class
member data. I don't follow the reason for example this code. I'am
quite confused

assingment operator
const B &operator=(const B& x){

if (&x != this)
a = x.a;

else
return *this;
}


This is how i see this code. its compares the reference of x to the
adress of the this pointer??

In a line like this, i don't follow the steps the compiler takes.
b1 = b2;

Code below



---------------------------------------------------------------------
#include <iostream>
using namespace std;


class A
{
int n ;

public:
A():n(0)
{
}
A(int x):n(x)
{
n = x;


}
A(A &c):n(){

n = c.n;
}


void print()
{ cout << n<<"\n\n";
}


A(const A& objectCopy){


n = objectCopy.n; // copy constructor


}
const A &operator=(const A x){
n = x.n; // Operator

}
void good(){
cout<< this->n<<"";
}

};


class B
{
A * a;

int v;

public:


B(A & x)
{


a = new A(x);


}


void print ()
{
a->print();
}
B(const B& copy){ // Class B copy constructor
a = copy.a;

}
const B &operator=(const B& x){


if (&x != this)
a = x.a;


else
return *this;



// return *this;
//delete a;
}
B::~B(){
delete a;


}

};


//-------------------------------------------------------------------------­--

int main()
{

{

A a1(5);
A a2(7);
B b1(a2);
b1.print();
B b2(a1);
b1 = b2;
b1.print();


a1.good();



}

cout << endl;
int trick;
cin >> trick;
return 0;
}


//-------------------------------------------------------------------------­-------
thnak you
 
V

Victor Bazarov

john said:
Hey,

I know we use the pointer this to obtain a class object or class
member data. I don't follow the reason for example this code. I'am
quite confused

assingment operator
const B &operator=(const B& x){

if (&x != this)
a = x.a;

else

'else' should be dropped.
return *this;
}


This is how i see this code. its compares the reference of x to the
adress of the this pointer??

No, it compares the _address_ of the 'x' object to the 'this' pointer.
In a line like this, i don't follow the steps the compiler takes.
b1 = b2;

Have you tried looking at assembly or stepping through the code in
a debugger? It helps.
Code below
[..snip..]

V
 
J

Jim Langston

john said:
Hey,

I know we use the pointer this to obtain a class object or class
member data. I don't follow the reason for example this code. I'am
quite confused

assingment operator
const B &operator=(const B& x){

if (&x != this)
a = x.a;

else
return *this;
}


This is how i see this code. its compares the reference of x to the
adress of the this pointer??

In a line like this, i don't follow the steps the compiler takes.
b1 = b2;

Code below

[snip code]

It's to check for self assignment. Consider.

myclass A;

A = A;

This could also occur using pointers. You get an instance of myclass using
new and through the course of the program wind up trying to assign the
instance to itself.

In a trivial program where a is a built in type it's not a problem. But
there are casses where you may be storing things on the stack. Consider the
case where a is actually a pointer. An assignment operator would be tempted
to do something like this:

// consider a to be an int pointer. consider size to be a variable with
it's size.
const B &operator=(const B& x)
{
delete a;
a = new int[x.size]
for ( size_t i = ; i < size; ++i )
a = x.a;

return *this;
}

Seems all well and good. We delete our current array, create a new one with
the proper size, then copy the contents. But what happens when self
assignment occurs? When x is actually this. As soon as we delete a we just
screwed up. We no longer have the memory to copy from, since we just
released it. That's where we check to make sure we aren't doing self
assignment.

const B &operator=(const B& x)
{
if ( &x != this )
{
delete a;
a = new int[x.size]
for ( size_t i = ; i < size; ++i )
a = x.a;
}

return *this;
}

this is a pointer to our current instance. It compares it with the address
of the instance to copy from. If they are the same, then self assignment is
occuring. We don't have to copy or assign anything, since we'd just be
copying from ourselves.
 
J

James Kanze

There is no reason for such code. It is completely incorrect.
[snip code]
It's to check for self assignment.

Which if necessary, is generally an indication of an error
elsewhere in the operator.
Consider.
myclass A;
This could also occur using pointers. You get an instance of myclass using
new and through the course of the program wind up trying to assign the
instance to itself.

Not just with new. In fact, most of the time, self assignment
occurs when working with arrays of the objects.
In a trivial program where a is a built in type it's not a problem.

If it's a problem, it's a problem with the assignment operator
of a.
But there are casses where you may be storing things on the
stack. Consider the case where a is actually a pointer. An
assignment operator would be tempted to do something like
this:
// consider a to be an int pointer. consider size to be a variable with
it's size.
const B &operator=(const B& x)
{
delete a;
a = new int[x.size]
for ( size_t i = ; i < size; ++i )
a = x.a;
return *this;
}

Seems all well and good.

No it doesn't. What happens if the new expression fails?
We delete our current array, create a new one with
the proper size, then copy the contents. But what happens when self
assignment occurs? When x is actually this. As soon as we delete a we just
screwed up. We no longer have the memory to copy from, since we just
released it. That's where we check to make sure we aren't doing self
assignment.

But the code is broken even without self-assignment. Checking
for self assignment doesn't fix this.
const B &operator=(const B& x)
{
if ( &x != this )
{
delete a;
a = new int[x.size]
for ( size_t i = ; i < size; ++i )
a = x.a;
}
return *this;
}


Which still has the same problem as the original. If the new
expression fails, you end up with an object that cannot be
destructed.
this is a pointer to our current instance. It compares it with the address
of the instance to copy from. If they are the same, then self assignment is
occuring. We don't have to copy or assign anything, since we'd just be
copying from ourselves.

The correct way of handling this is to build up the new object
first, before the delete:

B&
B::eek:perator=(
B const& other )
{
X* newA = new int[ other.size ] ;
for ( size_t i = 0 ; i < other.size ; ++ i ) {
newA[ i ] = other.a[ i ] ;
}
delete a ;
size = other.size ;
a = newA ;
return *this ;
}

Alternatively, you can use the swap idiom:

void
B::swap( B& other ) throw()
{
std::swap( size, other.size() ) ;
std::swap( a, other.a ) ;
}

B&
B::eek:perator=(
B const& other )
{
B tmp( other ) ;
swap( tmp ) ;
return *this ;
}

This has the advantage of being simple to understand. It's
widely used, and can be considered idiomatic C++. It's
supported by the standard library (e.g. all of the standard
containers have no-throw versions of swap).

You'll notice, of course, that no check for self assignment is
necessary.
 

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,772
Messages
2,569,593
Members
45,111
Latest member
VetaMcRae
Top