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


当前回答

Here's one example, given to me by @jleahy: Suppose you have a collection of tasks, executed asynchronously, and managed by an std::shared_ptr<Task>. You may want to do something with those tasks periodically, so a timer event may traverse a std::vector<std::weak_ptr<Task>> and give the tasks something to do. However, simultaneously a task may have concurrently decided that it is no longer needed and die. The timer can thus check whether the task is still alive by making a shared pointer from the weak pointer and using that shared pointer, provided it isn't null.

其他回答

Weak_ptr也可以很好地检查对象的正确删除——特别是在单元测试中。典型的用例可能是这样的:

std::weak_ptr<X> weak_x{ shared_x };
shared_x.reset();
BOOST_CHECK(weak_x.lock());
... //do something that should remove all other copies of shared_x and hence destroy x
BOOST_CHECK(!weak_x.lock());

共享指针有一个缺点: Shared_pointer不能处理父子周期依赖关系。如果父类使用父类的对象使用共享指针,则表示在同一文件中,如果子类使用父类的对象。共享指针将无法析构所有对象,甚至在循环依赖场景中共享指针根本不调用析构函数。基本上共享指针不支持引用计数机制。

我们可以使用weak_pointer来克服这个缺点。

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的循环引用。

我看到了很多有趣的答案,解释引用计数等,但我错过了一个简单的例子,演示如何使用weak_ptr防止内存泄漏。在第一个例子中,我在循环引用的类中使用shared_ptr。当类超出作用域时,它们不会被销毁。

#include<iostream>
#include<memory>
using namespace std;

class B;

class A
{
public:
    shared_ptr<B>bptr;
    A() {
        cout << "A created" << endl;
    }
    ~A() {
        cout << "A destroyed" << endl;
    }
};

class B
{
public:
    shared_ptr<A>aptr;
    B() {
        cout << "B created" << endl;
    }
    ~B() {
        cout << "B destroyed" << endl;
    }
};

int main()
{
    {
        shared_ptr<A> a = make_shared<A>();
        shared_ptr<B> b = make_shared<B>();
        a->bptr = b;
        b->aptr = a;
    }
  // put breakpoint here
}

如果你运行代码片段,你会看到类被创建,但没有被销毁:

A created
B created

现在我们把shared_ptr改成weak_ptr:

class B;
class A
{
public:
    weak_ptr<B>bptr;

    A() {
        cout << "A created" << endl;
    }
    ~A() {
        cout << "A destroyed" << endl;
    }
};

class B
{
public:
    weak_ptr<A>aptr;

    B() {
        cout << "B created" << endl;
    }
    ~B() {
        cout << "B destroyed" << endl;
    }
};

    int main()
    {
        {
            shared_ptr<A> a = make_shared<A>();
            shared_ptr<B> b = make_shared<B>();
            a->bptr = b;
            b->aptr = a;
        }
      // put breakpoint here
    }

这一次,当使用weak_ptr时,我们看到了正确的类破坏:

A created
B created
B destroyed
A destroyed

受到@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。