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中).
是的,移动的对象被破坏了.他们仍处于未确定但有效的状态.它们仍然是物体.
如果你还记得C++实际上并没有移动任何东西,那就最好了.std::move只给你一个右值.所谓的"移动构造函数"只是复制构造函数的简便替代方法,在查找时有rvalue,并允许您有机会交换类的封装数据而不是实际复制它.但是C++并没有为你移动任何东西,它无法分辨你何时做了一些移动.
因此,对于C++而言,如果我们甚至可以决定一般来说这意味着什么,从后来遭受破坏,那么对于C++来说,任何类型的规则都会停止"移出"对象将是不可能的危险和不切实际的.为移动的对象(例如通过nullptr在移动构造函数中设置源指针)使这种破坏安全(理想情况下是无操作),你会没事的.