• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 578
  • Last Modified:

Checking for self assignment

According to many C++ textbooks, you are supposed to check for self assignment when overloading the assignment operator. For instance, in Jesse Liberty's "Teach Yourself C++ in 21 Days" you find the following code to illustrate this

#include <iostream>
using namespace std;

class Cat
{
public:
      Cat();
      Cat(const Cat &);
      ~Cat();
      Cat & operator=(const Cat &);
      int getAge() const {return *itsAge;}
      int getWeight() const {return *itsWeight;}
      void setAge(int age) {*itsAge = age;}
private:
      int * itsAge;
      int * itsWeight;
};

Cat::Cat()
{
      itsAge = new int;
      itsWeight = new int;
      *itsAge = 5;
      *itsWeight = 9;
}

Cat::Cat(const Cat & cat)
{
      itsAge = new int;
      itsWeight = new int;
      *itsAge = cat.getAge();
      *itsWeight = cat.getWeight();
}

Cat::~Cat()
{      
      delete itsAge;
      itsAge = 0;
      delete itsWeight;
      itsWeight = 0;
}

Cat & Cat::operator=(const Cat & cat)
{
      if (this == &cat)    // CHECKS FOR SELF ASSIGNMENT
      {
            return *this;   // RETURNS *this IN CASE THE OBJECT IS ASSIGNED TO ITSELF
      }
      *itsAge = cat.getAge();
      *itsWeight = cat.getWeight();
      return *this;
}

int main()
{
      Cat frisky;
      cout << "frisky's age... " << frisky.getAge() << endl;
      cout << "frisky = frisky; "<< endl;
      frisky = frisky;
      cout << "frisky's age... " << frisky.getAge() << endl;
        return 0;
}

This code works fine. However, if you delete the "self assignment check" bit, it works fine too! So, is it really necessary to check for self assignment?
Thanks.
0
Rothbard
Asked:
Rothbard
1 Solution
 
dbkrugerCommented:
The example is nonsensical, and the way it is written, you do not need the self check.
Here's a better example (uncompiled)

class Matrix {
private:
  double* data;
  int rows, cols;
  void copy(const Matrix& orig) {
    for (int i = 0; i < rows*cols; i++)
      data[i] = orig.data[i];
  }
public:
  Matrix(int r, int c) : rows(r), cols(c) { data = new data[r*c]; }
  ~Matrix() { delete [] data; }

  Matrix(const Matrix& orig) {
    copy(orig);
  }

  Matrix& operator =(const Matrix& orig) {
    if (this == &orig) {
     return*this; // don't do self copy
   }
   delete [] data; // wipe out memory
   rows = orig.rows;
   cols = orig.cols;
   int size = rows * cols;
   data = new double[size];
   for (int i = 0; i < size;  i++)
    data[i] = orig.data[i];
    return *this;
  }
};

In this case, if you did a self copy, and did not have the check, the first thing you would delete the memory. Copying might work, but would be an error since that memory could in theory instantly be allocated somewhere else, not to mention be subtly corrupted by the delete itself.

Is this clearer?
0
 
RothbardAuthor Commented:
Thanks a lot for the explanation!
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now