移动成员函数生成

Move member function generation

本文关键字:函数 成员 移动      更新时间:2023-10-16

代码:

#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节防止隐式生成移动成员(见下文(。如果析构函数被移除,那么value是可移动构造的,也是可移动赋值的,正如我所期望的那样(http://ideone.com/VcR2eq)。

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

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

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

value::sstring时,类型的复制构造函数和复制赋值运算符被定义为已删除,因为s成员可复制的,因此value也是可复制的;CopyConstructable类型也是MoveConstructable,因为它在以下上下文中有效:

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

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