如何:创建和使用 weak_ptr 实例How to: Create and use weak_ptr instances

有时,对象必须存储一种方法来访问 shared_ptr 的基础对象,而不会导致引用计数递增。Sometimes an object must store a way to access the underlying object of a shared_ptr without causing the reference count to be incremented. 通常情况下,在实例之间具有循环引用时,会发生这种情况 shared_ptrTypically, this situation occurs when you have cyclic references between shared_ptr instances.

最佳设计是避免在任何时候都能实现指针的共享所有权。The best design is to avoid shared ownership of pointers whenever you can. 但是,如果您必须有实例的共享所有权 shared_ptr ,请避免它们之间存在循环引用。However, if you must have shared ownership of shared_ptr instances, avoid cyclic references between them. 如果无法避免循环引用,或者出于某种原因更可取,则使用 weak_ptr 向一个或多个所有者提供对另一个的弱引用 shared_ptrWhen cyclic references are unavoidable, or even preferable for some reason, use weak_ptr to give one or more of the owners a weak reference to another shared_ptr. 通过使用 weak_ptr ,可以创建一个 shared_ptr 联接到一组现有相关实例的,但前提是基础内存资源仍有效。By using a weak_ptr, you can create a shared_ptr that joins to an existing set of related instances, but only if the underlying memory resource is still valid. 本身并不 weak_ptr 参与引用计数,因此它无法阻止引用计数转到零。A weak_ptr itself does not participate in the reference counting, and therefore, it cannot prevent the reference count from going to zero. 但是,你可以使用 weak_ptr 来尝试获取用于初始化的的新副本 shared_ptrHowever, you can use a weak_ptr to try to obtain a new copy of the shared_ptr with which it was initialized. 如果已删除内存,则的 weak_ptr bool 运算符将返回 falseIf the memory has already been deleted, the weak_ptr's bool operator returns false. 如果内存仍有效,新的共享指针会递增引用计数,并保证只要 shared_ptr 变量保持在范围内,内存就有效。If the memory is still valid, the new shared pointer increments the reference count and guarantees that the memory will be valid as long as the shared_ptr variable stays in scope.

示例Example

下面的代码示例演示了一个用 weak_ptr 来确保正确删除具有循环依赖关系的对象的情况。The following code example shows a case where weak_ptr is used to ensure proper deletion of objects that have circular dependencies. 当你查看该示例时,假定它是在考虑了替代解决方案之后创建的。As you examine the example, assume that it was created only after alternative solutions were considered. Controller对象表示计算机进程的某个方面,它们独立运行。The Controller objects represent some aspect of a machine process, and they operate independently. 每个控制器都必须能够随时查询其他控制器的状态,并且每个控制器都包含一个专用 vector<weak_ptr<Controller>> 于此目的。Each controller must be able to query the status of the other controllers at any time, and each one contains a private vector<weak_ptr<Controller>> for this purpose. 每个向量都包含一个循环引用,因此 weak_ptr 使用的是实例,而不是 shared_ptrEach vector contains a circular reference, and therefore, weak_ptr instances are used instead of shared_ptr.

#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

class Controller 
{
public:
    int Num;
    wstring Status;
    vector<weak_ptr<Controller>> others;
    explicit Controller(int i) : Num(i) , Status(L"On")
    {
        wcout << L"Creating Controller" << Num << endl;
    }

    ~Controller()
    {
        wcout << L"Destroying Controller" << Num << endl;
    }

    // Demonstrates how to test whether the  
    // pointed-to memory still exists or not. 
    void CheckStatuses() const
    {
        for_each(others.begin(), others.end(), [] (weak_ptr<Controller> wp)
        {
            try
            {
                auto p = wp.lock();
                wcout << L"Status of " << p->Num << " = " << p->Status << endl;
            }

            catch (bad_weak_ptr b)
            {
                wcout << L"Null object" << endl;
            }                
        });
    }
};

void RunTest()
{
    vector<shared_ptr<Controller>> v;

    v.push_back(shared_ptr<Controller>(new Controller(0)));
    v.push_back(shared_ptr<Controller>(new Controller(1)));
    v.push_back(shared_ptr<Controller>(new Controller(2)));
    v.push_back(shared_ptr<Controller>(new Controller(3)));
    v.push_back(shared_ptr<Controller>(new Controller(4)));

    // Each controller depends on all others not being deleted. 
    // Give each controller a pointer to all the others. 
    for (int i = 0 ; i < v.size(); ++i)
    {
        for_each(v.begin(), v.end(), [v,i] (shared_ptr<Controller> p)
        {
            if(p->Num != i)
            {
                v[i]->others.push_back(weak_ptr<Controller>(p));
                wcout << L"push_back to v[" << i << "]: " << p->Num << endl;
            }
        });        
    }

    for_each(v.begin(), v.end(), [](shared_ptr<Controller>& p)
    {
        wcout << L"use_count = " << p.use_count() << endl;
        p->CheckStatuses();
    });
}

int main()
{    
    RunTest(); 
    wcout << L"Press any key" << endl;
    char ch;
    cin.getline(&ch, 1);
}
Creating Controller0
Creating Controller1
Creating Controller2
Creating Controller3
Creating Controller4
push_back to v[0]: 1
push_back to v[0]: 2
push_back to v[0]: 3
push_back to v[0]: 4
push_back to v[1]: 0
push_back to v[1]: 2
push_back to v[1]: 3
push_back to v[1]: 4
push_back to v[2]: 0
push_back to v[2]: 1
push_back to v[2]: 3
push_back to v[2]: 4
push_back to v[3]: 0
push_back to v[3]: 1
push_back to v[3]: 2
push_back to v[3]: 4
push_back to v[4]: 0
push_back to v[4]: 1
push_back to v[4]: 2
push_back to v[4]: 3
use_count = 1
Status of 1 = On
Status of 2 = On
Status of 3 = On
Status of 4 = On
use_count = 1
Status of 0 = On
Status of 2 = On
Status of 3 = On
Status of 4 = On
use_count = 1
Status of 0 = On
Status of 1 = On
Status of 3 = On
Status of 4 = On
use_count = 1
Status of 0 = On
Status of 1 = On
Status of 2 = On
Status of 4 = On
use_count = 1
Status of 0 = On
Status of 1 = On
Status of 2 = On
Status of 3 = On
Destroying Controller0
Destroying Controller1
Destroying Controller2
Destroying Controller3
Destroying Controller4
Press any key

作为试验,将 vector 修改 othersvector<shared_ptr<Controller>> ,然后在输出中,请注意,当返回时不调用析构函数 RunTestAs an experiment, modify the vector others to be a vector<shared_ptr<Controller>>, and then in the output, notice that no destructors are invoked when RunTest returns.

请参阅See also

智能指针(现代 C++)Smart Pointers (Modern C++)