移动语义如何与unique_ptr一起使用?

时间:2014-05-24 19:54:35

标签: c++ c++11 move-semantics unique-ptr

我正在尝试使用 unique_ptr 并编写一些简单的代码来检查它如何与移动语义一起使用。

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

class X
{
public:
    X(){}
    ~X() { cout << "Destructor X" << endl; }
    void Print() { cout << "X" << endl; }
};

int main()
{
    unique_ptr<X> ptr(new X());
    ptr->Print();

    vector<unique_ptr<X>> v;
    v.push_back(move(ptr));
    ptr->Print();
    v.front()->Print();

    return 0;
}

输出如下:

X
X
X
Destructor X

我的期望是在push_back之后原始的unique_ptr ptr 会失效。但Print()方法被调用就好了。这种行为会有什么解释?

2 个答案:

答案 0 :(得分:12)

  

我的期望是在push_back之后原始的unique_ptr ptr会失效。

它设置为空指针。您可以通过将其与nullptr进行比较来检查。

  

Print()方法被称为正常。对这种行为有什么解释?

您正在调用空指针上的成员函数,这是未定义的行为。该成员函数实际上并不访问类中的任何数据,因此它不会崩溃,但它仍然是未定义的行为。

您获得此程序的类似行为,它与unique_ptr无关:

int main()
{
  X x;
  X* ptr = &x;
  ptr->Print();
  ptr = nullptr;
  ptr->Print();
}

它似乎工作正常,因为X::Print()实际上没有从this指针读取任何内容。如果更改X::Print()的定义以访问类中的某些成员数据,则可能会因解除引用空指针而崩溃。

有关详细信息,请参阅When does invoking a member function on a null instance result in undefined behavior?

答案 1 :(得分:5)

你所拥有的是明确未定义的行为。如果我用以下

替换main的内容
int main()
{
    unique_ptr<X> ptr;
    ptr->Print();
    cout << (static_cast<bool>(ptr) ? "active\n" : "inactive\n");
}

gcc和clang仍然是print

X
inactive

你正在调用nullptr上的成员函数,我猜它恰好起作用,因为成员函数实际上并没有使用this指针。将您的班级定义更改为:

class X
{
    int y = 0;
public:
    X(){}
    ~X() { cout << "Destructor X" << endl; }
    void Print() { cout << "y = " << y << endl; }
};

现在您的原始代码会导致细分错误,因为它会尝试取消引用nullptr


至于你期望unique_ptr在你离开之后无效,你绝对是正确的。这是由标准保证的。

§20.8.1/ 4 [unique.ptr]

  

此外,u可以根据请求将所有权转让给另一个唯一指针u2。完成转移后,以下后置条件成立:
   - u2.p等于转帐前u.p
   - u.p等于nullptr
  ...

高于u&amp; u2unique_ptr个对象,p是指向托管对象的指针。