unique_ptr如何使用移动语义?

4

我正在尝试使用 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个回答

12

我的期望是在 push_back 后原本的 unique_ptr ptr 将失效。

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

Print() 方法仍然被调用。这种行为有何解释?

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

对于这个程序,你会得到类似的行为,这与 unique_ptr 无关:

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

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

请参见在空实例上调用成员函数何时会导致未定义行为?了解更多信息。


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,以及
...
上述uu2unique_ptr对象,p是所管理对象的指针。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接