【问题标题】:How do move semantics work with unique_ptr?移动语义如何与 unique_ptr 一起使用?
【发布时间】:2014-07-13 23:35:17
【问题描述】:

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

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

【问题讨论】:

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


    【解决方案1】:

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

    它被设置为一个空指针。您可以通过将其与 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?。

    【讨论】:

      【解决方案2】:

      你所拥有的是简单的未定义行为。如果我将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 & u2 上方是unique_ptr 对象,p 是指向托管对象的指针。

      【讨论】:

        猜你喜欢
        • 2013-04-07
        • 1970-01-01
        • 1970-01-01
        • 2014-12-18
        • 2012-04-14
        • 2020-05-20
        • 2011-05-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多