C++学习笔记-智能指针

智能指针本质上是原始指针的一种包装,它们自动管理内存,避免内存泄漏和悬空指针问题。C++11引入了三种主要的智能指针:unique_ptr、shared_ptr和weak_ptr。

智能指针的基本概念

 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
#include <iostream>
#include <memory>

class Entity
{
public:
    Entity() { std::cout << "Create Entity!" << std::endl; }
    ~Entity() { std::cout << "Destroy Entity!" << std::endl; }
    void Print() { std::cout << "Hello!" << std::endl; }
};

int main()
{
    // 传统的原始指针(不推荐)
    Entity* rawPtr = new Entity();
    rawPtr->Print();
    delete rawPtr;  // 容易忘记,导致内存泄漏
    
    // 使用智能指针(推荐)
    {
        auto smartPtr = std::make_unique<Entity>();
        smartPtr->Print();
        // 离开作用域时自动删除,无需手动delete
    }
}

unique_ptr - 独占所有权

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <memory>

int main()
{
    {
        // 创建unique_ptr的两种方式
        std::unique_ptr<Entity> uniqueEntity1(new Entity());  // 不推荐
        std::unique_ptr<Entity> uniqueEntity2 = std::make_unique<Entity>();  // 推荐,更安全
        
        uniqueEntity2->Print();
        
        // unique_ptr是唯一的,不能复制
        // std::unique_ptr<Entity> copy = uniqueEntity2;  // 编译错误
        
        // 但可以移动
        std::unique_ptr<Entity> moved = std::move(uniqueEntity2);
        // 现在uniqueEntity2为空,moved拥有对象
        
        if (uniqueEntity2 == nullptr)
            std::cout << "uniqueEntity2 is now null" << std::endl;
            
        moved->Print();
    }  // moved离开作用域,Entity自动销毁
}

unique_ptr的高级用法

 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
51
52
class Resource
{
private:
    std::string m_Name;
public:
    Resource(const std::string& name) : m_Name(name)
    {
        std::cout << "Create resource: " << m_Name << std::endl;
    }
    
    ~Resource()
    {
        std::cout << "Destroy resource: " << m_Name << std::endl;
    }
    
    void Use() const
    {
        std::cout << "Using resource: " << m_Name << std::endl;
    }
};

// 工厂函数返回unique_ptr
std::unique_ptr<Resource> CreateResource(const std::string& name)
{
    return std::make_unique<Resource>(name);
}

// 函数接受unique_ptr参数(转移所有权)
void ProcessResource(std::unique_ptr<Resource> resource)
{
    resource->Use();
    // 函数结束时resource被销毁
}

// 函数接受引用(不转移所有权)
void UseResource(const Resource& resource)
{
    resource.Use();
}

int main()
{
    auto resource1 = CreateResource("Resource1");
    UseResource(*resource1);  // 传递引用,不转移所有权
    
    auto resource2 = CreateResource("Resource2");
    ProcessResource(std::move(resource2));  // 转移所有权
    // resource2现在为空
    
    if (!resource2)
        std::cout << "resource2 is null after move" << std::endl;
}

shared_ptr - 共享所有权

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int main()
{
    std::shared_ptr<Entity> sharedEntity2;
    
    {
        // 创建shared_ptr
        std::shared_ptr<Entity> sharedEntity1 = std::make_shared<Entity>();  // 推荐,有更小的开销
        // std::shared_ptr<Entity> sharedEntity1(new Entity());  // 也可以,但开销更大
        
        sharedEntity2 = sharedEntity1;  // shared_ptr可以复制,内部维护一个引用计数
        
        std::cout << "Reference count: " << sharedEntity1.use_count() << std::endl;  // 输出: 2
        
        {
            std::shared_ptr<Entity> sharedEntity3 = sharedEntity1;
            std::cout << "Reference count: " << sharedEntity1.use_count() << std::endl;  // 输出: 3
        }  // sharedEntity3销毁,引用计数减1
        
        std::cout << "Reference count: " << sharedEntity1.use_count() << std::endl;  // 输出: 2
    }  // sharedEntity1销毁,引用计数减1
    
    std::cout << "Reference count: " << sharedEntity2.use_count() << std::endl;  // 输出: 1
    sharedEntity2->Print();
}  // sharedEntity2销毁,引用计数变为0,Entity被删除

shared_ptr的实际应用

 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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
class Player
{
private:
    std::string m_Name;
public:
    Player(const std::string& name) : m_Name(name)
    {
        std::cout << "Create player: " << m_Name << std::endl;
    }
    
    ~Player()
    {
        std::cout << "Destroy player: " << m_Name << std::endl;
    }
    
    const std::string& GetName() const { return m_Name; }
};

class Team
{
private:
    std::vector<std::shared_ptr<Player>> m_Players;
    std::string m_Name;
    
public:
    Team(const std::string& name) : m_Name(name) {}
    
    void AddPlayer(std::shared_ptr<Player> player)
    {
        m_Players.push_back(player);
        std::cout << player->GetName() << " joined team " << m_Name << std::endl;
    }
    
    void RemovePlayer(const std::string& playerName)
    {
        auto it = std::find_if(m_Players.begin(), m_Players.end(),
            [&playerName](const std::shared_ptr<Player>& player) {
                return player->GetName() == playerName;
            });
            
        if (it != m_Players.end())
        {
            std::cout << (*it)->GetName() << " left team " << m_Name << std::endl;
            m_Players.erase(it);
        }
    }
    
    void ListPlayers() const
    {
        std::cout << "Team " << m_Name << " players:" << std::endl;
        for (const auto& player : m_Players)
        {
            std::cout << "  - " << player->GetName() 
                      << " (refs: " << player.use_count() << ")" << std::endl;
        }
    }
};

int main()
{
    auto player1 = std::make_shared<Player>("Alice");
    auto player2 = std::make_shared<Player>("Bob");
    
    {
        Team teamA("Red Team");
        Team teamB("Blue Team");
        
        teamA.AddPlayer(player1);
        teamA.AddPlayer(player2);
        teamB.AddPlayer(player1);  // player1同时在两个队伍中
        
        teamA.ListPlayers();
        teamB.ListPlayers();
        
        teamA.RemovePlayer("Alice");
        std::cout << "After removing Alice from Red Team:" << std::endl;
        teamB.ListPlayers();  // Alice仍在Blue Team中
    }  // 队伍销毁,但玩家对象可能仍然存在
    
    std::cout << "Teams destroyed, player1 refs: " << player1.use_count() << std::endl;
}

weak_ptr - 弱引用

 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
int main()
{
    std::weak_ptr<Entity> weakEntity;
    
    {
        std::shared_ptr<Entity> sharedEntity = std::make_shared<Entity>();
        weakEntity = sharedEntity;  // weak_ptr不会增加引用计数
        
        std::cout << "shared_ptr count: " << sharedEntity.use_count() << std::endl;  // 输出: 1
        std::cout << "weak_ptr expired: " << weakEntity.expired() << std::endl;     // 输出: false
        
        // 从weak_ptr获取shared_ptr
        if (auto shared = weakEntity.lock())
        {
            shared->Print();
            std::cout << "Successfully accessed object through weak_ptr" << std::endl;
        }
    }  // sharedEntity销毁,Entity被删除
    
    std::cout << "weak_ptr expired: " << weakEntity.expired() << std::endl;  // 输出: true
    
    // 尝试从已过期的weak_ptr获取shared_ptr
    if (auto shared = weakEntity.lock())
    {
        shared->Print();
    }
    else
    {
        std::cout << "Entity has been destroyed, cannot access through weak_ptr" << std::endl;
    }
}

weak_ptr解决循环引用问题

 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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
class Child;

class Parent
{
private:
    std::vector<std::shared_ptr<Child>> m_Children;
    std::string m_Name;
    
public:
    Parent(const std::string& name) : m_Name(name)
    {
        std::cout << "Create parent: " << m_Name << std::endl;
    }
    
    ~Parent()
    {
        std::cout << "Destroy parent: " << m_Name << std::endl;
    }
    
    void AddChild(std::shared_ptr<Child> child);
    const std::string& GetName() const { return m_Name; }
};

class Child
{
private:
    std::weak_ptr<Parent> m_Parent;  // 使用weak_ptr避免循环引用
    std::string m_Name;
    
public:
    Child(const std::string& name) : m_Name(name)
    {
        std::cout << "Create child: " << m_Name << std::endl;
    }
    
    ~Child()
    {
        std::cout << "Destroy child: " << m_Name << std::endl;
    }
    
    void SetParent(std::shared_ptr<Parent> parent)
    {
        m_Parent = parent;
    }
    
    void CallParent()
    {
        if (auto parent = m_Parent.lock())
        {
            std::cout << m_Name << " calling parent " << parent->GetName() << std::endl;
        }
        else
        {
            std::cout << m_Name << "'s parent is no longer available" << std::endl;
        }
    }
    
    const std::string& GetName() const { return m_Name; }
};

void Parent::AddChild(std::shared_ptr<Child> child)
{
    m_Children.push_back(child);
    child->SetParent(shared_from_this());  // 需要继承std::enable_shared_from_this
}

// 修正版本的Parent类
class BetterParent : public std::enable_shared_from_this<BetterParent>
{
private:
    std::vector<std::shared_ptr<Child>> m_Children;
    std::string m_Name;
    
public:
    BetterParent(const std::string& name) : m_Name(name)
    {
        std::cout << "Create parent: " << m_Name << std::endl;
    }
    
    ~BetterParent()
    {
        std::cout << "Destroy parent: " << m_Name << std::endl;
    }
    
    void AddChild(std::shared_ptr<Child> child)
    {
        m_Children.push_back(child);
        child->SetParent(shared_from_this());
    }
    
    const std::string& GetName() const { return m_Name; }
};

自定义删除器

 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
class FileHandle
{
private:
    FILE* m_File;
    std::string m_Filename;
    
public:
    FileHandle(const std::string& filename) : m_Filename(filename)
    {
        m_File = fopen(filename.c_str(), "w");
        if (m_File)
            std::cout << "Opened file: " << filename << std::endl;
    }
    
    ~FileHandle()
    {
        if (m_File)
        {
            fclose(m_File);
            std::cout << "Closed file: " << m_Filename << std::endl;
        }
    }
    
    FILE* Get() const { return m_File; }
};

int main()
{
    // 使用自定义删除器
    auto filePtr = std::unique_ptr<FileHandle, std::function<void(FileHandle*)>>(
        new FileHandle("test.txt"),
        [](FileHandle* f) {
            std::cout << "Custom deleter called" << std::endl;
            delete f;
        }
    );
    
    // 或者使用shared_ptr的自定义删除器
    auto sharedFile = std::shared_ptr<FileHandle>(
        new FileHandle("shared_test.txt"),
        [](FileHandle* f) {
            std::cout << "Shared custom deleter called" << std::endl;
            delete f;
        }
    );
}

性能考虑

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// make_shared vs shared_ptr(new T)
void PerformanceComparison()
{
    // 方式1:make_shared(推荐)
    // 只进行一次内存分配,对象和控制块在同一块内存中
    auto ptr1 = std::make_shared<Entity>();
    
    // 方式2:shared_ptr(new T)
    // 进行两次内存分配,对象和控制块分开
    std::shared_ptr<Entity> ptr2(new Entity());
    
    // make_shared更高效,但在某些情况下可能延迟内存释放
}

总结

  1. 智能指针本质:原始指针的一种包装,自动管理内存
  2. unique_ptr:独占所有权指针,不能复制但可以移动,销毁时自动删除对象
  3. shared_ptr:共享所有权指针,内部维护引用计数,引用计数为0时自动删除对象
  4. weak_ptr:弱引用指针,与shared_ptr一起使用,不影响引用计数,主要用于解决循环引用问题
  5. 最佳实践:优先使用make_unique和make_shared,避免直接使用new
updatedupdated2025-09-202025-09-20