12

代码:

#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/VcR2eqvalue,它是可移动的并且是可移动的。

但是,当 的定义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 没有用户声明的析构函数,并且
- 移动构造函数不会被隐式定义为已删除。
4

1 回答 1

9

std::is_move_constructible<T>如果std::is_constructible<T, T&&>为真,则为真,但这并不意味着这样的构造将调用移动构造函数,只是可以从相同类型的右值构造类型。这样的构造可能使用复制构造函数。

类型的复制构造函数和复制赋值运算符何时value::sunique_ptr定义为已删除,因为该s成员不可复制。它没有移动构造函数和移动赋值运算符,因为正如您所指出的,它有一个用户声明的析构函数。这意味着它没有复制构造函数和移动构造函数(并且没有其他可以接受 type 参数的用户定义的构造函数value&&),所以std::is_constructible<value, value&&>是错误的。

When value::sis astring类型的复制构造函数和复制赋值运算符 未定义为已删除,因为该s成员是可复制的,因此value也是可复制的,并且 CopyConstructible 类型也是 MoveConstructible 的,因为它在此上下文中有效:

value v1;
value v2 = std::move(v1);  // calls copy constructor

这意味着std::is_constructible<value, value&&>是真的,即使它调用的是复制构造函数而不是移动构造函数。

于 2013-06-03T14:57:43.690 回答