CS253: Software Development with C++

Fall 2021

Rule Of Three

Show Lecture.RuleOfThree as a slide show.

CS253 Rule Of Three

The Rule of Three

The Rule of Three states that if a class defines any of these methods, called the “Big Three”, then it should probably define all of them:

There are certainly exceptions to this rule. Fortunately, the rule says “probably”.

When none of the Big Three are needed

class Hero {
    string name;
  public:
    Hero(string n) : name(n) { }
    auto who() const { return name; }
};
Hero h1("Superman"), h2(h1);
cout << h1.who() << ' ' << h2.who();
Superman Superman

No problem

Problem

class Hero {
    char *name;
  public:
    Hero(const char *n) {
        name = new char[strlen(n)+1];
        copy(n, n+strlen(n)+1, name);
    }
    ~Hero() { delete[] name; }
    auto who() const { return name; }
};
Hero h1("Superman");
cout << h1.who();
Superman

It works well so far. Let’s try using the compiler-generated copy ctor.

Problem

class Hero {
    char *name;
  public:
    Hero(const char *n) {
        name = new char[strlen(n)+1];
        copy(n, n+strlen(n)+1, name);
    }
    ~Hero() { delete[] name; }
    auto who() const { return name; }
};
Hero h1("Superman"), h2(h1);
cout << h1.who() << ' ' << h2.who();
free(): double free detected in tcache 2
SIGABRT: Aborted

Problem with copy ctor

Problem with assignment operator

Solution #1

class Hero {
    char *name;
  public:
    Hero(const char *n) {
        name = new char[strlen(n)+1];
        copy(n, n+strlen(n)+1, name);
    }
    Hero(const Hero &rhs) {
        name = new char[strlen(rhs.name)+1];
        copy(rhs.name, rhs.name+strlen(rhs.name)+1, name);
    }
    Hero &operator=(const Hero &rhs) {
        delete[] name;
        name = new char[strlen(rhs.name)+1];
        copy(rhs.name, rhs.name+strlen(rhs.name)+1, name);
        return *this;
    }
    ~Hero() { delete[] name; }
    auto who() const { return name; }
};
Hero h1("Superman"), h2(h1);
cout << h1.who() << ' ' << h2.who();
Superman Superman

Solution #2

class Hero {
    char *name = nullptr;
    void set(const char *p) {
        delete[] name;
        name = new char[strlen(p)+1];
        copy(p, p+strlen(p)+1, name);
    }
  public:
    Hero(const char *n) { set(n); }
    Hero(const Hero &rhs) { set(rhs.name); }
    Hero &operator=(const Hero &rhs) {
        set(rhs.name);
        return *this;
    }
    ~Hero() { delete[] name; }
    auto who() const { return name; }
};
Hero h1("Superman"), h2(h1);
cout << h1.who() << ' ' << h2.who();
Superman Superman

It gets worse

Move methods

string where="base", what="ball";
string sport = where+what;
cout << sport;
baseball

Move methods