【问题标题】:Why need to set rvalue reference to null in move constructor?为什么需要在移动构造函数中将右值引用设置为 null?
【发布时间】:2015-11-20 19:49:44
【问题描述】:

我已阅读帖子:Why do we need to set rvalue reference to null in move constructor?

它说在移动过程中,您只是将指针从一个对象复制到另一个对象,因此两个指针指向临时对象。当临时对象超出范围时,它的析构函数将运行。然后由 2 个指针指向的对象将被释放。所以move构造函数构造的object的指针域会指向不可用的地方。

不过,看看下面的代码:

int *p = new int(3);
int *q = p;
delete p;
std::cout << *q << std::endl;

删除指针p后,指针q仍然可以访问int对象。

那么,是不是因为对象被右值引用访问的时候会造成差异?

【问题讨论】:

  • @zenith 抱歉,只是一个错误。我已经重新编辑了
  • @sydridgm 您在这段代码中究竟在哪里看到右值引用和移动构造?也许选择你自己的标题。
  • @LogicStuff 我发布的代码只是一个测试。无来源
  • 您复制了一个指针值,然后删除了底层对象。指针 q 的后续取消引用导致未定义的行为。据我所知,您还没有使用 std::move() ...
  • 您的代码已损坏,但如果您想查看一个可能的问题,请尝试致电delete q;。如果你很幸运,它会崩溃并显示一个很好的错误消息。

标签: c++ move rvalue


【解决方案1】:

不,你不能。它似乎有效,但它完全是未定义的行为。内存被释放到运行时。

当您移动某物时,您实际上是在说原始对象不再有效 - 您只能从移动到的对象访问其原始内容。此外,在移动后设置为 NULL 可防止双重删除 - 当原始对象超出范围并尝试释放该内存时,它将立即失败(如果新对象已经释放它)或新对象对象在尝试释放该内存时会失败。

【讨论】:

  • 实际上,内存并没有释放到操作系统,而是释放到运行时。不同之处在于它通常仍属于该程序。如果它已发布到操作系统,则尝试读取它的通常响应将是 SEGFAULT。
【解决方案2】:

Accessing deleted memory of the free store is undefined behavior.

在移动构造时,构造对象的指针被设置为右值的指针,之后又被设置为nullptr
右值引用的对象 此后结束其生命周期,毕竟它是一个临时的。因此,设置为nullptr 的指针预计不再使用。当它被破坏时,delete nullptr; 被执行,即无操作。
OTOH,当 构造对象 的生命周期结束时,实际资源是 deleted - 指向它的指针是在移动构造函数中分配的。

【讨论】:

    【解决方案3】:

    不,删除指针 p 后,指针 q 不能仍然访问 int 对象。如果您不这么认为,因为您运行它并在输出中得到 3 - 那是因为您导致了未定义的行为,并且 UB 可以作为其众多选项之一“工作”。

    通常情况是内存地址还没有被重用,仍然属于程序(所以它有访问权限并且值没有被擦除),所以你会看到任何值被删除那个记忆。所有这一切意味着它看起来好像代码完全没问题,而实际上它不是。在这种情况下,您也可以使用 *p 进行打印,并且没有什么不同。 p 和 q 变量都包含相同的地址...被删除释放。

    其中一个有趣的方面是,高安全性应用程序或 GPG 等加密应用程序会用垃圾手动填充已删除的内存,这样它就不会被嗅出——将私钥的访问权提供给全世界。否则,密钥仍然会被写入 RAM,直到有人在那里写入其他内容!

    【讨论】:

      【解决方案4】:

      这是指针的问题。它们不传达所有权语义。

      您应该使用std::unique_ptr 之类的东西。当您将指针从一个对象移动到另一个对象时,旧对象会识别出它不再拥有该对象,因此您无法访问数据。

      简单的解决方案。像 C++ 社区的其他人一样,停止使用这样的指针。

      std::unqieu_ptr<int> p(new int(3));
      std::unique_ptr<int> q = p;              // Fails to compile
      
      
      std::unqieu_ptr<int> p(new int(3));
      std::unique_ptr<int> q = std::move(p);   // explicitly transfer ownership.
      
      
      // delete p;  // No longer need this as when the onbject goes out of scope
                    // it is deleted.
      

      【讨论】:

        【解决方案5】:

        您链接的问题和您的问题都试图避免在取消引用 q 时出现未定义的行为。

        问题是,(在链接的问题中)您必须知道通过将其设置为 nullptr,您不能再取消引用 q(您不管理它)。但是在这里,您的职责是不要在 delete 之后取消引用 q。可以预见的是,q 会在std::cout &lt;&lt; *q &lt;&lt; std::endl; 之前被删除。取消引用是你的错!

        尽管如此,将 q 设置为 nullptr 有助于调试,delete q 不再是 UB,nullptr 表示指向不存在对象的指针。

        【讨论】:

          猜你喜欢
          • 2014-04-02
          • 2013-08-11
          • 1970-01-01
          • 2019-01-22
          • 2020-04-26
          • 1970-01-01
          • 2017-01-10
          • 1970-01-01
          • 2015-07-18
          相关资源
          最近更新 更多