关于 unique_ptr 所有权转让的问题

Questions about the ownership transfer of unique_ptr

对于以下代码:

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

using namespace std;

struct pm
{
    pm() : a(make_unique<vector<int>>(1, 10)){};
    unique_ptr<vector<int>> a;
};

struct parms
{
    parms() : a(make_unique<pm>()){};
    unique_ptr<pm> a;
};

class test
{
public:
    test() : p(make_unique<parms>()) {}

    unique_ptr<const parms> getParms()
    {
        return move(p);
    }

    void setParms(int b)
    {
        p->a->a->push_back(b);
    }

    void pp()
    {
        cout << p->a->a->at(0) << "\n";
    }

private:
    unique_ptr<parms> p;
};

int main()  
{  
    auto t = make_unique<test>();  
    t->pp();
    cout << t->getParms()->a->a->at(0) << "\n";
    cout << (t->getParms()==nullptr) << "\n";  ;  
}

t->getParms() 在我们 "cout << t->getParms()->a->a->at(0) << "\n"; 之后是一个 nullptr。

如果我们对 ptr 做同样的事情,

int main()  
{  
    auto t = make_unique<test>();  
    t->setParms(5);
    t->pp(); 
    auto ptr = t->getParms();  
    cout << ptr->a->a->at(0) << "\n";  
    cout << (ptr==nullptr) << "\n";  ;  
}

ptr 不是 nullptr。

我的问题是:为什么 cout t->getParms(),然后 t->getParms() 是 nullptr 而 prt 不是?是因为unique_ptr的life scope吗?还是临时右值?这种行为背后的原因是什么?

您的方法 getParams() 将所有权转移给调用者。

unique_ptr<const parms> getParms()
{
    return move(p);
}

成员移动到 return 值,现在调用者拥有指针对象。您没有在此处存储 returned 值:

cout << t->getParms()->a->a->at(0) << "\n";

尽管如此,即使您这样做了,t 也不再拥有 param,因此当您再次询问 t 时:

cout << (t->getParms()==nullptr) << "\n";  ;  

它不知道 param 了。


在第二个示例中,您将所有权从 t 转移到 ptr

auto ptr = t->getParms();  

现在 ptr 拥有 param。您可以随时检查指针或值:

cout << ptr->a->a->at(0) << "\n";  
cout << (ptr==nullptr) << "\n";  ;  

这两条线没有所有权转移。


What's the reason behind this behavior?

如上所述,原因是 getParams() 将所有权转移给调用者。这对于 getter 方法来说相当不常见。也许“stealer-method”会是一个更好的名字;)。如果你不想放弃所有权(并且你确定指针是有效的)你可以简单地 return 一个参考:

const parms& getParms() const { return *p; }

My question is: why cout t->getParms(), then t->getParms() is a nullptr but prt is not?

t->getParms() 将所有权转移给调用者。这会将 t->p 设置为空。由于 t->p 不再拥有指针,所以当您第二次调用 t->getParms() 时,没有任何东西可以传递。

您从未从 ptr 转让所有权,因此它尚未设置为空。