【问题标题】:using unique_ptr after move移动后使用 unique_ptr
【发布时间】:2017-07-30 14:10:45
【问题描述】:

我不明白为什么这段代码有效:

class Base {
public:
    virtual void doStuff() const{}
    Base(Base & b) = delete;
    Base() {
        cout << "Base" << endl;
    }
    ~Base() {
        cout << "~Base" << endl;
    }
    friend ostream& operator<<(ostream& out, const Base& a) {
         return out << "me";
    }
};
int main(){
    unique_ptr<Base> pt = make_unique<Base>();
    auto npt = move(pt);
    auto &a = *pt;

    if (pt == nullptr)
        cout << "yes nullptr" << endl;
    cout << a << endl;
}

Visual Studio 2015 中的输出是:

Base
yes nullptr
me
~Base

所以它不会崩溃,pt 在被移出后甚至可以使用。 在 coliru 在线编译器中,它在cout &lt;&lt; a &lt;&lt; endl; 行崩溃。我不明白它为什么不会在auto &amp;a = *pt; 行崩溃,因为此时 pt 等于 nullptr 并且命令 auto &amp;refToNull= nullptr; 是编译错误。

我会感谢您对正在发生的事情进行澄清。

【问题讨论】:

  • 未定义的行为是未定义的。
  • 您忘记了您的operator&lt;&lt; 函数不是成员函数。这是一个全局非成员函数。尝试调用一个实际的成员函数,或者访问一个成员变量。
  • 所以它不会崩溃,pt 被移出后甚至可以使用。 谁说它应该总是崩溃?这是未定义的行为。
  • 你的例子归结为Base&amp; a = *(Base*)nullptr; cout &lt;&lt; a; 以同样的方式展示UB,我预测会产生同样的结果。 unique_ptrmove 与它无关 - 它们只是形成了一种非常精细的拼写 (Base*)nullptr 的方式。

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


【解决方案1】:

首先声明

auto &a = *pt;

是一种未定义的行为,即未定义。在 C++ 中取消引用 nullptr 不会使您的程序崩溃,它可能会发生任何事情。


您可能对代码的期望是 segmentation fault,但它不会发生,因为您实际上从未访问过对象 a

确实,您的operator&lt;&lt; 采用了Base 对象,但它根本不使用它。

相反,如果您尝试执行以下操作:

friend ostream& operator<<(ostream& out, const Base& a) {
     a.do_stuff();
}

您的程序将被操作系统杀死,因为 a 对象在错误的内存(实际上是 0x0 内存)上被引用。

关于 nullptr 取消引用的相关问题是 Here

【讨论】:

    【解决方案2】:

    auto npt = move(pt);pt 的所有权转让给npt,留下ptnullptr。因为pt 现在是nullptr,所以if (pt == nullptr) cout &lt;&lt; "yes nullptr" &lt;&lt; endl; 正确输出“yes nullptr”。

    auto &amp;a = *pt; 表示您正在尝试取消引用 nullptr 这只是一个未定义的行为cout &lt;&lt; a &lt;&lt; endl; 可能导致任何事情都可能发生,但不一定会导致程序崩溃。

    【讨论】:

      猜你喜欢
      • 2013-04-07
      • 1970-01-01
      • 2023-03-30
      • 1970-01-01
      • 1970-01-01
      • 2021-06-01
      • 2014-07-26
      • 2014-07-13
      • 2019-07-14
      相关资源
      最近更新 更多