C/C++ Arena

Step 7 of 8

The rule of zero

The last few steps showed how much careful code a class needs when it holds a raw owning pointer: a destructor, a deep-copying copy constructor, copy assignment, and (later) move operations. Getting all of them right is hard, and it's easy to forget one.

The modern answer: don't hold raw owning pointers. Use members that already manage themselves:

Their own destructors, copies and moves are correct, and the compiler-generated versions for your class simply call theirs, member by member. So you write none of the special functions. This is the rule of zero, and it's how most classes in modern C++ are written.

#include <iostream>
#include <string>
#include <vector>

class Playlist {
public:
    void add(const std::string& song) { songs_.push_back(song); }
    int count() const { return songs_.size(); }
    const std::string& first() const { return songs_.front(); }

private:
    std::string name_ = "mix";
    std::vector<std::string> songs_;
};

int main() {
    Playlist a;
    a.add("intro");
    a.add("outro");
    Playlist b = a;
    b.add("bonus");
    std::cout << a.count() << " " << b.count() << " " << b.first() << "\n";
}
2 3 intro

Copying a into b makes a real, independent copy of the vector of strings, with no code from you. Destroying both frees everything correctly.

When do you still write them?

Only in low-level classes whose whole job is to wrap one resource (like the IntArray you just wrote, or a wrapper for a C library handle). Everything else composes those building blocks and follows the rule of zero.

Your task

Write class Inventory with the rule of zero: void add(const std::string& item), int count() const, bool has(const std::string& item) const, void clear(). No new, no delete, no destructor.

Challenge 2

Write class Team with the rule of zero: void add(const std::string& name), bool remove(const std::string& name) (removes the first match, returns whether it found one), and std::vector<std::string> names() const. No new, no delete, no destructor.

Challenge 3

Write class History that keeps only the last N messages, with N given to the constructor: void push(const std::string& msg) adds a message and drops the oldest when there are more than N, and std::vector<std::string> last() const returns them oldest first. Rule of zero again.

Previous: Copy assignment with copy-and-swap Next: Challenge: a scope guard