Home Item 7 (1/2) - Smart pointers(English)
Post
Cancel

Item 7 (1/2) - Smart pointers(English)

Smart Pointers

When you see an int* ptr being used in your C++ code, do you need to delete it after use? If yes, should you use delete[] ptr or delete ptr? If the later code performs a delete, repeating the delete will cause a crash. If no, and no subsequent code performs the delete, it will cause a memory leak. You must have encountered the above dilemma, and smart pointers are here to solve this problem! (How wonderful)

In C++, smart pointers provide a safe and automated way of managing resources. C++11 introduced several different types of smart pointers, including std::unique_ptr, std::shared_ptr, and std::weak_ptr.

Each smart pointer has its specific use case and advantages.

Below are the usage scenarios and examples of these three types of smart pointers.

std::unique_ptr

std::unique_ptr is a smart pointer that ensures exclusive ownership of a resource, ensuring that at any given time, only one pointer owns the resource.

This prevents resource leaks and duplicate releases of resources.

Usage scenarios:

  1. When you want a certain object to have only one owner.
  2. To implement the RAII (Resource Acquisition Is Initialization) pattern.
  3. To avoid copying and sharing of pointers.
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
46
47
48
49
50
#include <iostream>
#include <memory>

class Resource {
public:
    Resource() { std::cout << "Resource acquired : "<< this << "\n"; }
    ~Resource() { std::cout << "Resource destroyed : "<< this <<"\n"; }
    void sayHello() const { std::cout << "Hello, Resource from : " << this <<"\n"; }
};

int main() {

    std::cout << "~Enter scope" << std::endl;
    {
        std::unique_ptr<Resource> res1(new Resource());
        res1->sayHello();

        // Transfer ownership
        std::unique_ptr<Resource> res2 = std::move(res1);
        if (!res1) {
            std::cout << "res1 is null\n";
        }
        res2->sayHello();
        // Resource will be automatically destroyed when res2 goes out of scope
    }

    std::cout << "~Leave scope" << std::endl;
    std::cout << "------------" << std::endl;

    std::cout << "~Enter scope" << std::endl;
    {
        int size = 3;
        std::unique_ptr<Resource[]> res1 = std::make_unique<Resource[]>(size);

        for (size_t i = 0; i < size; i++)
        {
            res1[i].sayHello();
        }

        // Transfer ownership
        std::unique_ptr<Resource[]> res2 = std::move(res1);
        if (!res1) {
            std::cout << "res1 is null\n";
        }

    }
    std::cout << "~Leave scope" << std::endl;

    return 0;
}

Automatically releases resources when going out of scope.

c++11 make_unique supports the creation of dynamic arrays

1
std::make_unique<Resource[]>(3);

Execution result Desktop View

std::shared_ptr

std::shared_ptr is a smart pointer that allows multiple pointers to share ownership of the same resource. The resource is automatically released when the last pointer pointing to the resource is destroyed.

Usage scenarios:

  1. When you need multiple owners to share the same resource.
  2. When the lifecycle of the resource needs to be shared among multiple objects or functions.
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
#include <iostream>
#include <memory>

class Resource {
 public:
     Resource() { std::cout << "Resource acquired : " << this << "\n"; }
     ~Resource() { std::cout << "Resource destroyed : " << this << "\n"; }
     void sayHello() const { std::cout << "Hello, Resource from : " << this << "\n"; }
};

int main() {
     std::shared_ptr<Resource> res1 = std::make_shared<Resource>();
     std::cout << "res1.use_count : " << res1.use_count() << std::endl;

     std::cout << "~Enter scope" << std::endl;
     {
         std::shared_ptr<Resource> res2 = res1;
         res2->sayHello();
         std::cout << "res1.use_count : " << res1.use_count() << std::endl;
         std::cout << "res2.use_count : " << res2.use_count() << std::endl;

         std::cout << "res2 goes out of scope\n";
     }
     std::cout << "~Leave scope" << std::endl;

     std::cout << "res1.use_count : " << res1.use_count() << std::endl;
     res1->sayHello();
     std::cout << "res1 goes out of scope\n";

     // Resource will be automatically destroyed when res1 goes out of scope
     return 0;
}

use_count() can show how many shared pointers hold the resource.

When res2 goes out of scope, it releases its ownership of the resource.

In C++11, make_shared does not support the creation of dynamic arrays yet.

Desktop View

Creating a dynamic array will result in the following error.

1
std::shared_ptr<Resource[]> res1 = std::make_shared<Resource[]>(3);

Desktop View

☝ツ☝

This post is licensed under CC BY 4.0 by the author.

👈 ツ 👍