代码:
#include <iostream>
#include <ios>
#include <string>
#include <type_traits>
#include <memory>
struct value
{
~value() = default;
std::unique_ptr<std::string> s;
};
int main()
{
std::cout << std::boolalpha;
std::cout << std::is_move_constructible<value>::value << '\n';
std::cout << std::is_move_assignable<value>::value << '\n';
using str_ptr = std::unique_ptr<std::string>;
std::cout << std::is_move_constructible<str_ptr>::value << '\n';
std::cout << std::is_move_assignable<str_ptr>::value << '\n';
return 0;
}
输出(使用 g++ v4.7.2 编译,http ://ideone.com/CkW1tG ):
错误的 错误的 真的 真的
正如我所料,value
不可移动且不可移动,因为:
~value() = default;
是一个用户声明的析构函数,它根据第12.8节(见下文)防止隐式生成移动成员。如果析构函数被删除,那么正如我所期望的那样( http://ideone.com/VcR2eq)value
,它是可移动的并且是可移动的。
但是,当 的定义value
更改为(http://ideone.com/M8LHEA)时:
struct value
{
~value() = default;
std::string s; // std::unique_ptr<> removed
};
输出是:
真的 真的 真的 真的
value
出乎意料地移动可构造和移动可分配。我是误解还是这是编译器错误?
背景:我提供了这个问题的答案,并被告知Tree<>
是可移动的,但我不确定并且正在尝试确定它是否是可移动的。
第8.4.2节c++11 标准(草案 n3337)的显式默认函数:
显式默认函数和隐式声明函数统称为默认函数,实现应为它们提供隐式定义(12.1 12.4、12.8),这可能意味着将它们定义为已删除。一个特殊的成员函数是用户提供的,如果它是用户声明的并且在其第一次声明时没有显式地默认或删除。用户提供的显式默认函数(即,在其第一次声明后显式默认)在显式默认的位置定义;如果这样的函数被隐式定义为已删除,则程序格式错误。[注意:在第一次声明后将函数声明为默认函数可以提供高效的执行和简洁的定义,同时为不断发展的代码库提供稳定的二进制接口。—结束注释]
第12.8 节复制和移动类对象(第 9 点):
如果类 X 的定义没有显式声明移动构造函数, 一个将被隐式声明为默认当且仅当 - X 没有用户声明的复制构造函数, - X 没有用户声明的复制赋值运算符, - X 没有用户声明的移动赋值运算符, - X 没有用户声明的析构函数,并且 - 移动构造函数不会被隐式定义为已删除。