对象跟对象之间是有所有权关系的,这些关系可以用shared_ptrweak_ptrunique_ptr来表达。但是今天先不提智能指针的事情,先来谈谈什么是所有权。

直接的讲,C++ 里面的对象所有权的关系,指的是谁负责delete谁的关系。让我们来看几个例子,假设类 A 的一个成员变量是一个指向了类 B 的实例的指针。

独占所有权:如果 A 对 B 有独占所有权的话,那么 A delete B。这里面也包含着另一层意思,如果 C 想要持有 B,那么就必须让 A 放弃对 B 的所有权,把它的成员变量设置为nullptr。现在就由 C 来决定在什么时候 deleteB,这个对象跟 A 再也没有关系了。独占的意思就是不分享,而且所有权也是可以转移的,转移后仍然是独占。

分享所有权:如果 A 对 B 有分享所有权的话,那么 B 由最后一个持有该对象的 A 来delete。如果 C 想要持有 B,那么 A 这个时候不需要放弃对 B 的所有权,转而将讲所有权分享给 C。如果所有的 A 都没有了,C 还在的话,那么由 C 来决定什么时候 deleteB。如果 C 首先放弃了所有权(譬如说 C 自己被delete了),那么仍然由最后一个持有 B 的 A 来 deleteB。

弱引用:如果 A 对 B 有弱引用的话,那么 A 不负责 deleteB,但是 A 可以使用 B。如果 B 已经被拥有所有权的对象delete了,那么 A 会收到通知。这个时候如果 A 还想试图使用 B,就会拿到一个nullptr

最后一种就是普通的指针了。普通的指针没有任何功能,指向的对象被delete了你也不知道,稍微不注意就容易炸裂。所以这就是为什么 C++ 推荐我们使用这一套智能指针来管理对象与对象之间的关系,因为只要好好使用,程序永远不会“Access Violation”。

既然学习了对象的所有权关系,那么 C++ 是怎么来表达它的呢?现在让我们先来看一下独占关系的例子。

#include <iostream>
#include <string>
#include <memory>

using namespace std;

class A
{
public:
    string name;

    A(const string& theName)
        :name{ theName }
    {
    }
};

int main()
{
    // unique_ptr<A> x;
    auto x = make_unique<A>("A");
    cout << x->name << endl;

    unique_ptr<A> y(x.release());
    if (x)
    {
        cout << "x不为空" << endl;
    }
    else
    {
        cout << "x为空" << endl;
    }
    cout << y->name << endl;
    return 0;
}

如果我们要x放弃对A*指针的所有权的话,要调用x.release(),这个函数返回原本独占的A*。这个时候我们就可以拿已经不归任何人所有的指针来构造一个新的unique_ptr

我们可以通过把unique_ptr转换为bool值来判断一个独占的执政指针是否为空。

接下来让我们看一下shared_ptrweak_ptr的例子。

#include <iostream>
#include <string>
#include <memory>

using namespace std;

class A
{
   
public:
    string name;

    A(const string& theName)
        :name{
    theName }
    {
   
    }
};

int main()
{
   
    // shared_ptr<A> x;
    auto x = make_shared<A>("A");
    cout << x->name << endl;

    {
   
        // shared_ptr<A> y;
        auto y = x;
        cout << y->name << endl;
    }

    weak_ptr<A> w = x;
    {
   
        // shared_ptr<A> y;
        auto y = w.lock();
        cout << x->name << endl;
    }

    x = nullptr;
    {
   
        auto y = w.lock();
        if (y)
        {
   
            cout << "w不为空" << endl;
        }
        else
        {
   
            cout << "w为空" << endl;
        }
    }
    return 0;
}

首先,make_shared我们都知道了,在之前的章节里面已经对shared_ptr有所介绍了。

第二,shared_ptr可以复制很多个,譬如说auto y = x;。这个时候xyA都有所有权。因此在输出了第二行之后,y被释放了,x还在,所以对象还在。

第三,我们可以从shared_ptr构造一个weak_ptr。如果我们需要使用weak_ptr所指向的对象的话,要调用lock函数。这个函数会返回一个shared_ptr

接下来就是x = nullptr;。我们已经把其他指针(在这里是空指针)赋值给x,这个时候已经没有任何shared_ptr拥有对A的所有权了,所以A就在此刻被delete

最后,我们会发现,因为w指向的原来的对象已经被delete了,所以lock会返回一个空的shared_ptr

最后要提到的是,unique_ptrshared_ptr都有get函数,在不放弃所有权的情况下返回指向的对象的指针。它们还有reset函数,其实跟把nullptr赋值给他们是一样的。

weak_ptrexpired函数来告诉我们它指向的对象是不是还在,如果我们仅仅是为了做判断,不需要去调用lock函数。

shared_ptr 存在环形引用的情况
以上来自计蒜客 ?