Post

Rule of Five

Rule of Five

Rule of Five


Prerequisites


1. What is Rule of Five

The Rule of Five states:

If a class manages resources and defines one of these:

  • destructor
  • copy constructor
  • copy assignment operator

Then it should also define:

  • move constructor
  • move assignment operator

If your class manages resources, you should explicitly define all five special member functions.

2. Why Do We Need It?

C++ classes often manage:

  • dynamic memory (new/delete)
  • file handles
  • sockets
  • mutexes

Use when:

  • managing raw resources
  • using new/delete
  • handling ownership manually

❌ Default Behavior Problem

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class A
{
    int* data;

public:
    A(int v)
    {
        data = new int(v);
    }

    ~A()
    {
        delete data;
    }
};

Issue

1
2
A a1(10);
A a2 = a1;  // shallow copy
  • Both objects point to the same memory
  • double delete → crash

3. The Five Functions

3-1. Destructor

1
2
3
4
~A()
{
    delete data;
}

releases resource

3-2. Copy Constructor

1
2
3
4
A(const A& other)
{
    data = new int(*other.data);
}

deep copy

3-3. Copy Assignment Operator

1
2
3
4
5
6
7
8
9
A& operator=(const A& other)
{
    if (this != &other)
    {
        delete data;
        data = new int(*other.data);
    }
    return *this;
}

3-4. Move Constructor

1
2
3
4
5
A(A&& other) noexcept
{
    data = other.data;
    other.data = nullptr;
}

transfers ownership (no copy)

3-5. Move Assignment Operator

1
2
3
4
5
6
7
8
9
10
11
A& operator=(A&& other) noexcept
{
    if (this != &other)
    {
        delete data;

        data = other.data;
        other.data = nullptr;
    }
    return *this;
}

4. Performance Perspective

❌ Copy

1
alloc → copy → slow

✔️ Move

1
pointer transfer → fast

Move avoids:

  • allocation
  • deep copy
  • expensive operations

4-1. Stable Design

❌ Missing self-assignment check
1
if (this != &other)
❌ Not using noexcept
1
A(A&& other) noexcept;

required for STL optimizations

5. Full Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class A
{
    int* data;

public:
    A(int v) : data(new int(v)) {}

    ~A()
    {
        delete data;
    }

    A(const A& other)
    {
        data = new int(*other.data);
    }

    A& operator=(const A& other)
    {
        if (this != &other)
        {
            delete data;
            data = new int(*other.data);
        }
        return *this;
    }

    A(A&& other) noexcept
    {
        data = other.data;
        other.data = nullptr;
    }

    A& operator=(A&& other) noexcept
    {
        if (this != &other)
        {
            delete data;

            data = other.data;
            other.data = nullptr;
        }
        return *this;
    }
};

6. Rule of Zero / One / Three / Five

RuleMeaningFocusWhen to UseKey Functions
Rule of ZeroDo not define any special member functionsNo manual resource managementUse STL containers / smart pointersNone
Rule of OneOne class manages one resource (RAII principle)Single responsibility for a resourceDesigning simple resource wrappersTypically destructor (and possibly others)
Rule of ThreeIf one is defined, define all threeSafe copying of resourcesWhen managing raw resources (C++98 style)Destructor, Copy Constructor, Copy Assignment
Rule of FiveRule of Three + move semanticsEfficient resource transferWhen performance matters (C++11+)+ Move Constructor, Move Assignment
This post is licensed under CC BY 4.0 by the author.