C++ 11 创建和使用共享 weak_ptr

Posted dsw846

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ 11 创建和使用共享 weak_ptr相关的知识,希望对你有一定的参考价值。

有时对象必须存储一种方法,用来在不引起引用计数增加的情况下访问 shared_ptr 的基础对象。通常,当您在 shared_ptr 实例之间循环引用时,就会出现此情况。

最佳的设计能够尽可能地避免指针具有共享所有权。但是,如果您必须具有共享的 shared_ptr 实例所有权,请避免在实例之间进行循环引用。如果循环引用不可避免,甚至由于某种原因而更为可取,请使用 weak_ptr 为一个或多个所有者提供对其他 shared_ptr 的弱引用。使用 weak_ptr,您可以创建连接到现有相关实例组的 shared_ptr,但仅当基础内存资源有效时才行。 weak_ptr 本身并不参与引用计数,因此,它无法阻止引用计数转到为零。但是,您可以使用 weak_ptr 来尝试获取 shared_ptr 的新副本,通过使用该副本进行初始化。如果内存已被删除,则会引发 bad_weak_ptr 异常。如果内存仍有效,则新的共享指针会递增引用计数,并确保只要 shared_ptr 变量保持在范围内,内存就有效。

    {
        std::tr1::shared_ptr<std::string> fPtr1(new std::string("demo"));
        std::cout << "before weak fPtr1 use_cout:" << fPtr1.use_count() << std::endl;
        std::tr1::weak_ptr<std::string> fPtr2 = fPtr1;
        std::cout << "after  weak fPtr1 use_cout:" << fPtr1.use_count() << std::endl;
        if (!fPtr2.expired())
        {
            std::shared_ptr<std::string> fPtr3 = fPtr2.lock();
            std::cout << "fPtr1 use_cout:" << fPtr1.use_count() << std::endl;
            std::shared_ptr<std::string> fPtr4 = fPtr2.lock();
            std::shared_ptr<std::string> fPtr5 = fPtr2.lock();
            std::cout << "fPtr1 use_cout:" << fPtr1.use_count() << " and fPtr2 use_count:" << fPtr2.use_count() << std::endl;
        }
        
    }

 

下面的代码示例演示了使用 weak_ptr 以确保正确删除循环依赖关系对象的实例。检查示例时,假定它是仅在考虑备用解决方案后才创建的。 Controller对象表示设备处理的某个方面,并且能独立运行。每个控制器必须能够在任何时间查询其他控制器的状态,因此,每个控制器包含私有vector<weak_ptr<Controller>>。由于每个向量包含一个循环引用,因此使用 weak_ptr 实例而不是 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);
}


输出:
创建 Controller0
创建 Controller1
创建 Controller2
创建 Controller3
创建 Controller4
push_back 到 v[0]: 1
push_back 到 v[0]: 2
push_back 到 v[0]: 3
push_back 到 v[0]: 4
push_back 到 v[1]: 0
push_back 到 v[1]: 2
push_back 到 v[1]: 3
push_back 到 v[1]: 4
push_back 到 v[2]: 0
push_back 到 v[2]: 1
push_back 到 v[2]: 3
push_back 到 v[2]: 4
push_back 到 v[3]: 0
push_back 到 v[3]: 1
push_back 到 v[3]: 2
push_back 到 v[3]: 4
push_back 到 v[4]: 0
push_back 到 v[4]: 1
push_back 到 v[4]: 2
push_back 到 v[4]: 3
use_count = 1
1 的状态 = 打开
2 的状态 = 打开
3 的状态 = 打开
4 的状态 = 打开
use_count = 1
0 的状态 = 打开
2 的状态 = 打开
3 的状态 = 打开
4 的状态 = 打开
use_count = 1
0 的状态 = 打开
1 的状态 = 打开
3 的状态 = 打开
4 的状态 = 打开
use_count = 1
0 的状态 = 打开
1 的状态 = 打开
2 的状态 = 打开
4 的状态 = 打开
use_count = 1
0 的状态 = 打开
1 的状态 = 打开
2 的状态 = 打开
3 的状态 = 打开
正在销毁 Controller0
正在销毁 Controller1
正在销毁 Controller2
正在销毁 Controller3
正在销毁 Controller4
按任意键

作为练习,将向量 others 修改为 vector<shared_ptr<Controller>>,然后在输出中,注意当 TestRun 返回时,未调用析构函数。

以上是关于C++ 11 创建和使用共享 weak_ptr的主要内容,如果未能解决你的问题,请参考以下文章

C++ shared_ptr&&weak_ptr的简单介绍和仿写

c++中weak_ptr到底是干啥用的?

C++ 智能指针(shared_ptr/weak_ptr)源码分析

c++新特性11 (12)weak_ptr

c++新特性11 (12)weak_ptr

C++ 智能指针(shared_ptr/weak_ptr)源码分析