我开始研究c++ 11的智能指针,我没有看到std::weak_ptr有任何有用的用途。有人能告诉我什么时候std::weak_ptr是有用的/必要的吗?


当前回答

Shared_ptr:保存真实对象。

weak_ptr:使用lock连接到真正的所有者,否则返回NULL shared_ptr。

大致来说,weak_ptr角色类似于房屋中介的角色。如果没有中介,要想租到房子,我们可能得在城里随机找房子。中介会确保我们只去那些还能租到的房子。

其他回答

受到@offirmo回复的启发,我写了这段代码,然后运行visual studio诊断工具:

#include <iostream>
#include <vector>
#include <memory>

using namespace std;

struct Member;
struct Team;

struct Member {
    int x = 0;

    Member(int xArg) {
        x = xArg;
    }

    shared_ptr<Team> teamPointer;
};

struct Team {
    vector<shared_ptr<Member>> members;
};

void foo() {
    auto t1 = make_shared<Team>();
    for (int i = 0; i < 1000000; i++) {
        t1->members.push_back(make_shared<Member>(i));
        t1->members.back()->teamPointer = t1;
    }
}

int main() {
    foo();

    while (1);

    return 0;
}

当指向团队的成员指针是shared_ptr teamPointer时,在foo()完成后内存就没有空闲了,即它停留在150mb左右。

但是如果在诊断工具中将其更改为weak_ptr teamPointer,您将看到一个峰值,然后内存使用量恢复到大约2MB。

Shared_ptr:保存真实对象。

weak_ptr:使用lock连接到真正的所有者,否则返回NULL shared_ptr。

大致来说,weak_ptr角色类似于房屋中介的角色。如果没有中介,要想租到房子,我们可能得在城里随机找房子。中介会确保我们只去那些还能租到的房子。

http://en.cppreference.com/w/cpp/memory/weak_ptr Std::weak_ptr是一个智能指针,它持有对Std::shared_ptr管理的对象的非所有(“弱”)引用。它必须转换为std::shared_ptr才能访问被引用的对象。

Std::weak_ptr建模临时所有权:当一个对象只有在它存在时才需要访问,并且它可能在任何时候被其他人删除时,Std::weak_ptr用于跟踪该对象,并将其转换为Std::shared_ptr以承担临时所有权。如果原始的std::shared_ptr在此时被销毁,对象的生命周期将被延长,直到临时的std::shared_ptr也被销毁。

此外,std::weak_ptr用于打破std::shared_ptr的循环引用。

缓存就是一个很好的例子。

对于最近访问的对象,您希望将它们保存在内存中,因此可以保留一个指向它们的强指针。定期扫描缓存,确定最近没有访问哪些对象。你不需要把它们保存在内存中,所以你去掉强指针。

但是,如果该对象正在使用,而其他一些代码持有指向它的强指针,该怎么办?如果缓存删除了指向该对象的唯一指针,就再也找不到它了。因此,缓存保留了一个弱指针,指向它需要找到的对象,如果它们碰巧留在内存中。

这正是弱指针所做的——它允许你在一个对象仍然在附近时定位它,但如果没有其他东西需要它,它就不会保留它。

它们在Boost中很有用。当调用异步处理程序时,不能保证目标对象仍然存在。诀窍是使用std::bind或lambda capture将weak_ptr绑定到异步处理程序对象中。

void MyClass::startTimer()
{
    std::weak_ptr<MyClass> weak = shared_from_this();
    timer_.async_wait( [weak](const boost::system::error_code& ec)
    {
        auto self = weak.lock();
        if (self)
        {
            self->handleTimeout();
        }
        else
        {
            std::cout << "Target object no longer exists!\n";
        }
    } );
}

这是在Boost中经常看到的self = shared_from_this()习惯用法的变体。Asio示例,其中挂起的异步处理程序不会延长目标对象的生命周期,但如果目标对象被删除,则仍然是安全的。