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

viv*_*an2 3 c++ unique-ptr move-semantics c++11

我正在尝试使用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;
}
Run Code Online (Sandbox Code Playgroud)

输出如下:

X
X
X
Destructor X
Run Code Online (Sandbox Code Playgroud)

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

Jon*_*ely 12

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

它被设置为空指针.您可以通过比较来检查nullptr.

但这个Print()方法被称为正常.这种行为会有什么解释?

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

你得到这个程序的类似行为,它与unique_ptr以下内容无关:

int main()
{
  X x;
  X* ptr = &x;
  ptr->Print();
  ptr = nullptr;
  ptr->Print();
}
Run Code Online (Sandbox Code Playgroud)

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

请参阅何时在null实例上调用成员函数会导致未定义的行为?欲获得更多信息.


Pra*_*ian 5

你所拥有的是明确未定义的行为.如果我更换的内容main与以下

int main()
{
    unique_ptr<X> ptr;
    ptr->Print();
    cout << (static_cast<bool>(ptr) ? "active\n" : "inactive\n");
}
Run Code Online (Sandbox Code Playgroud)

gcc和clang都打印出来

X
inactive
Run Code Online (Sandbox Code Playgroud)

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

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

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


至于unique_ptr你离开它后会失效的期望,你是绝对正确的.这是标准的保证.

§20.8.1/ 4 [unique.ptr]

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

Above u&u2unique_ptr对象,p是指向托管对象的指针.