被移动的物体仍被破坏?

phs*_*phs 7 c++ destructor raii move-semantics c++11

在学习C++ 11时,我对移动对象的行为方式感到惊讶.考虑以下代码:

#include <exception>
#include <iostream>
#include <type_traits>

class Moveable {
public:
  Moveable() {
    std::cout << "Acquire odd resource\n";
  }

  ~Moveable() noexcept(false) {
    std::cout << "Release odd resource\n";
    // if (!std::uncaught_exception() && error_during_release) {
    //   throw std::exception("error");
    // }
  }

  Moveable(Moveable const &) = delete;
  Moveable &operator=(Moveable const &) = delete;

  Moveable(Moveable &&) = default;
  Moveable &operator=(Moveable &&) = default;
};

int main(int argc, char *argv[]) {
  static_assert(!std::is_copy_constructible<Moveable>::value,
    "is not copy constructible");
  static_assert(!std::is_copy_assignable<Moveable>::value, "is not copy assignable");
  static_assert(std::is_move_constructible<Moveable>::value, "is move constructible");
  static_assert(std::is_move_assignable<Moveable>::value, "is move assignable");

  Moveable moveable{};
  Moveable moved{std::move(moveable)};
  Moveable moved_again{std::move(moved)};
}
Run Code Online (Sandbox Code Playgroud)

它产生这个输出:

$ clang++ --version
clang version 3.8.0 (tags/RELEASE_380/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /opt/clang+llvm-3.8.0-x86_64-linux-gnu-ubuntu-14.04/bin
$ clang++ --std=c++14 --stdlib=libc++ -Wall -Werror -o move_and_destroy move_and_destroy.cc  && ./move_and_destroy
Acquire odd resource
Release odd resource
Release odd resource
Release odd resource
Run Code Online (Sandbox Code Playgroud)

我很惊讶,因为我希望创建一个可移动的RAII类型.然而似乎每个移动的中间体都被破坏了!

是否有一些变体允许我在"对象的生命周期"结束时释放我的资源?(也就是说,在移动对象序列的生命周期结束时?)

处于类似情况的人应该使用std::unique_ptr并完成.但是在这种情况下,有可能~Moveable()抛出,显然std::unique_ptr析构函数将在异常时终止程序(至少在clang 3.8.0中).

Lig*_*ica 9

是的,移动的对象被破坏了.他们仍处于未确定但有效的状态.它们仍然是物体.

如果你还记得C++实际上并没有移动任何东西,那就最好了.std::move只给你一个右值.所谓的"移动构造函数"只是复制构造函数的简便替代方法,在查找时有rvalue,并允许有机会交换类的封装数据而不是实际复制它.但是C++并没有为你移动任何东西,它无法分辨你何时做了一些移动.

因此,对于C++而言,如果我们甚至可以决定一般来说这意味着什么,从后来遭受破坏,那么对于C++来说,任何类型的规则都会停止"移出"对象将是不可能的危险和不切实际的.为移动的对象(例如通过nullptr在移动构造函数中设置源指针)使这种破坏安全(理想情况下是无操作),你会没事的.

  • 要补充的是,再次将移动的对象设置为正确的值是完全有效的。例如,`std::uniqiue_ptr&lt;X&gt; px = std::move(old); 旧 = std::make_unique&lt;X&gt;();` (2认同)