While learning C++11, I was surprised by the way moved objects appear to behave. Consider this code:
#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)};
}
It yields this output:
$ 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
I'm surprised because I was hoping to create a movable RAII type. However it seems each moved intermediate is destructed!
Is there some variation of this that allows me to release my resource once at the end of my "object's lifetime"? (that is, at the end of the lifetimes of the sequence of moved objects?)
Someone in a similar situation should probably use std::unique_ptr
and be done. However in this scenario it is possible for ~Moveable()
to throw, and apparently std::unique_ptr
's destructor will terminate the program on exception (at least, in clang 3.8.0.)
std::unique_ptr
internally checks for null pointer and it doesn't release the resource if it's null to avoid this problem – Harrington