Rule of Three

Sometimes you need to implement a class that manages a resource. (Never manage multiple resources in a single class, this will only lead to pain.) In that case, remember the rule of three:

If you need to explicitly declare either the destructor, copy constructor or copy assignment operator yourself, you probably need to explicitly declare all three of them
class Foo
{
    char* _text;

public:
    // Regular constructor
    Foo(const char* text) : _text(new char[std::strlen(text) + 1])
    {
        std::strcpy(_text, text);
    }

    // Copy constructor
    Foo(const Foo& other)
    {
        _text = new char[std::strlen(other._text) + 1];
        std::strcpy(_text, other._text);
    }
    
    // Destructor
    ~Foo()
    {
        delete[] _text;
    }
    
    // Copy operator
    Foo& operator=(Foo other)
    {
        std::swap(_text, other._text);
        return *this;
    }

};

NOTE: A good implementation also uses a custom swap function

Rule of Five

class Foo
{
    char* _text;

public:
    
    // Regular constructor
    Foo(const char* text) : _text(new char[std::strlen(text) + 1])
    {
        std::strcpy(_text, text);
    }
    
    // Copy constructor
    Foo(const Foo& other)
    {
        _text = new char[std::strlen(other._text) + 1];
        std::strcpy(_text, other._text);
    }
    
    // Move constructor
    Foo(Foo&& other) : _text(other._text)
    {
        other._text = nullptr;
    }
    
    // Destructor
    ~Foo()
    {
        delete[] _text;
    }
    
    // Copy operator
    Foo& operator=(Foo other)
    {
        std::swap(_text, other._text);
        return *this;
    }

};

Reference: The rule of three/five/zero