What is wrong with “checking for self-assignment” and what does it mean?

A question that’s of greater importance in this case would be:


  • “What does it mean, when a you write function in a way, that requires you to check for self assignment???”

To answer my rhetorical question: It means that a well-designed assignment operator should not need to check for self-assignment. Assigning an object to itself should work correctly (i.e. have the end-effect of “doing nothing”) without performing an explicit check for self-assignment.

For example, if I wanted to implement a simplistic array class along the lines of

class array {
    // code...
 
    int *data;
    size_t n;
};

…and came up with the following implementation of the assignment operator…

array &array::operator =(const array &rhs) 
{
    delete[] data;

    n = rhs.n;
    data = new int[n];

    std::copy_n(rhs.data, n, data);

    return *this;
}
That implementation would be considered “bad” since it obviously fails in case of self-assignment.

In order to “fix” this, you have two options;

  1. Add an explicit self-assignment check
array &array::operator =(const array &rhs) {
    if (&rhs != this) {
        delete[] data;

        n = rhs.n;
        data = new int[n];

        std::copy_n(rhs.data, n, data);
    }
    return *this;
}
  1. Follow a “check-less” approach:
array &array::operator =(const array &rhs) {
      size_t new_n = rhs.n;
      int *new_data = new int[new_n];

      std::copy_n(rhs.data, new_n, new_data);

      delete[] data;

      n = new_n;
      data = new_data;

      return *this;
}

The latter approach is better in a sense that it works correctly in self-assignment situations without making an explicit check. This implementation is far for perfect from a ‘safety point of view’, it is here to illustrate the difference between “checked” and “check-less” approaches to handling self-assignment. The later check-less implementation can be written more elegantly through the well-known copy-and-swap idiom.

This does not mean that you should avoid explicit checks for self-assignment. Such check do make sense from the performance point of view: there’s no point in carrying out a long sequence of operations just to end up “doing nothing” in the end. But in a well-designed assignment operator such checks should not be necessary from the correctness point of view.

Leave a Comment