# shared_ptr 和 weak_ptr

URL: https://caijiao.org/cpp/stl/shared_ptr
Source: docs/cpp/stl/shared_ptr.md
Description: 本节介绍 C++ 中的 'shared_ptr' 和 'weak_ptr' 智能指针，帮助理解它们如何管理动态内存，解决共享所有权和避免循环引用问题。

在 C++ 中，`shared_ptr` 和 `weak_ptr` 是智能指针的一种，旨在提供更安全、自动的内存管理方式。它们属于 C++11 标准库中的智能指针，通常用于管理共享所有权和避免内存泄漏。它们解决了裸指针的许多问题，尤其是在复杂的对象管理中。

## shared_ptr

`shared_ptr` 是一种智能指针，它允许多个指针共同拥有一个资源。当最后一个指向资源的 `shared_ptr` 被销毁时，资源会自动释放。它提供了引用计数的机制，用于追踪有多少个 `shared_ptr` 指向相同的对象。

### 创建 shared_ptr

`shared_ptr` 可以通过 `std::make_shared` 或构造函数来创建。推荐使用 `make_shared`，因为它比直接使用构造函数更加高效。

### 示例：创建 shared_ptr

```cpp
#include <iostream>
#include <memory>  // 引入 shared_ptr 所在的头文件

using namespace std;

class MyClass {
public:
    MyClass() { cout << "MyClass Constructor\n"; }
    ~MyClass() { cout << "MyClass Destructor\n"; }
    void show() { cout << "Hello, MyClass!\n"; }
};

int main() {
    // 使用 make_shared 创建 shared_ptr
    shared_ptr<MyClass> ptr1 = make_shared<MyClass>();
    ptr1->show();
    
    // 使用 shared_ptr 构造函数创建
    shared_ptr<MyClass> ptr2 = shared_ptr<MyClass>(new MyClass());
    ptr2->show();

    // shared_ptr 会在最后一个指针超出作用域时自动释放内存
    return 0;
}
````

输出：

```
MyClass Constructor
Hello, MyClass!
MyClass Constructor
Hello, MyClass!
MyClass Destructor
MyClass Destructor
```

### shared\_ptr 的常见操作

* `use_count()`：获取当前有多少个 `shared_ptr` 指向相同的对象。
* `reset()`：重置 `shared_ptr`，释放当前对象，并使其为空指针。
* `get()`：获取裸指针，但不影响引用计数。

### 示例：use\_count 和 reset

```cpp
#include <iostream>
#include <memory>

using namespace std;

class MyClass {
public:
    MyClass() { cout << "MyClass Constructor\n"; }
    ~MyClass() { cout << "MyClass Destructor\n"; }
    void show() { cout << "Hello, MyClass!\n"; }
};

int main() {
    shared_ptr<MyClass> ptr1 = make_shared<MyClass>();
    shared_ptr<MyClass> ptr2 = ptr1;  // 共享所有权
    cout << "Reference count: " << ptr1.use_count() << endl;  // 输出 2

    ptr2.reset();  // 重置 ptr2
    cout << "Reference count after reset: " << ptr1.use_count() << endl;  // 输出 1

    return 0;
}
```

输出：

```
MyClass Constructor
Reference count: 2
Reference count after reset: 1
MyClass Destructor
```

## weak\_ptr

`weak_ptr` 是一种特殊的智能指针，它与 `shared_ptr` 配合使用，用于解决循环引用的问题。`weak_ptr` 不增加对象的引用计数，它仅仅观察资源是否存在。当 `shared_ptr` 被销毁时，`weak_ptr` 不会阻止资源的销毁。

### 为什么使用 weak\_ptr？

在某些情况下，多个 `shared_ptr` 可能会相互引用，导致它们永远无法释放资源，形成循环引用。`weak_ptr` 可以打破循环引用，允许对象的生命周期由 `shared_ptr` 管理，同时避免了强引用导致的资源泄漏。

### 示例：使用 weak\_ptr 解决循环引用

```cpp
#include <iostream>
#include <memory>

using namespace std;

class A;

class B {
public:
    shared_ptr<A> a_ptr;  // B 持有 A 的 shared_ptr
};

class A {
public:
    weak_ptr<B> b_ptr;  // A 使用 weak_ptr 持有 B 的指针，避免循环引用
    void show() { cout << "Hello from A!\n"; }
};

int main() {
    shared_ptr<A> a = make_shared<A>();
    shared_ptr<B> b = make_shared<B>();
    
    a->b_ptr = b;  // A 持有 B 的弱引用
    b->a_ptr = a;  // B 持有 A 的强引用

    cout << "End of program\n";
    return 0;
}
```

输出：

```
End of program
```

在此例中，`A` 和 `B` 之间的相互引用通过 `weak_ptr` 打破了循环引用，避免了内存泄漏。

### weak\_ptr 的常见操作

* `lock()`：将 `weak_ptr` 转换为 `shared_ptr`。如果对象已经被销毁，`lock()` 会返回一个空的 `shared_ptr`。
* `expired()`：检查所指向的对象是否已经被销毁。

### 示例：使用 weak\_ptr 和 lock()

```cpp
#include <iostream>
#include <memory>

using namespace std;

class MyClass {
public:
    MyClass() { cout << "MyClass Constructor\n"; }
    ~MyClass() { cout << "MyClass Destructor\n"; }
    void show() { cout << "Hello, MyClass!\n"; }
};

int main() {
    weak_ptr<MyClass> weakPtr;
    {
        shared_ptr<MyClass> sharedPtr = make_shared<MyClass>();
        weakPtr = sharedPtr;  // weak_ptr 观察 shared_ptr
        sharedPtr->show();

        // 使用 weak_ptr 的 lock() 获取 shared_ptr
        shared_ptr<MyClass> lockedPtr = weakPtr.lock();
        if (lockedPtr) {
            lockedPtr->show();
        }
    }  // sharedPtr 超出作用域，内存释放

    // 再次尝试 lock()，此时资源已销毁
    shared_ptr<MyClass> lockedPtr2 = weakPtr.lock();
    if (!lockedPtr2) {
        cout << "Object has been destroyed\n";  // 输出 Object has been destroyed
    }

    return 0;
}
```

输出：

```
MyClass Constructor
Hello, MyClass!
Hello, MyClass!
MyClass Destructor
Object has been destroyed
```

## 总结

* `shared_ptr`：实现了资源的共享所有权，通过引用计数管理内存，确保当所有 `shared_ptr` 都不再使用时，资源会自动释放。
* `weak_ptr`：不增加引用计数，用于解决循环引用问题，它观察 `shared_ptr` 管理的资源，但不会阻止资源的销毁。

通过合理使用 `shared_ptr` 和 `weak_ptr`，可以高效且安全地管理 C++ 中的动态内存，避免内存泄漏和循环引用等常见问题。
