Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/160.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ `=default`移动构造函数是否等同于成员移动构造函数?_C++_C++11_Constructor_Default_Move Semantics - Fatal编程技术网

C++ `=default`移动构造函数是否等同于成员移动构造函数?

C++ `=default`移动构造函数是否等同于成员移动构造函数?,c++,c++11,constructor,default,move-semantics,C++,C++11,Constructor,Default,Move Semantics,这是吗 相当于 struct Example { int a, b; Example(int mA, int mB) : a{mA}, b{mB} { } Example(const Example& mE) : a{mE.a}, b{mE.b} { } Example(Example&& mE) : a{move(mE.a)}, b{move(mE.b)} { } Example&am

这是吗

相当于

struct Example { 
    int a, b; 
    Example(int mA, int mB) : a{mA}, b{mB}               { }
    Example(const Example& mE) : a{mE.a}, b{mE.b}        { }
    Example(Example&& mE) : a{move(mE.a)}, b{move(mE.b)} { }
    Example& operator=(const Example& mE) { a = mE.a; b = mE.b; return *this; } 
    Example& operator=(Example&& mE)      { a = move(mE.a); b = move(mE.b); return *this; } 
}

除了非常病理的病例。。。对


更准确地说,您还必须考虑
示例
可能具有的最终基础,以及完全相同的规则。首先是基础-按声明顺序-然后是成员,始终按声明顺序。

是的,两者都是相同的。

但是

此版本允许您跳过主体定义

但是,在声明显式默认函数时,必须遵循一些规则:

8.4.2显式默认函数[dcl.fct.def.default]

表单的函数定义:

struct Example { 
    int a, b; 
    Example(int mA, int mB) : a{mA}, b{mB} { }
    Example(const Example& mE)            = default;
    Example(Example&& mE)                 = default;
    Example& operator=(const Example& mE) = default;
    Example& operator=(Example&& mE)      = default;
}
称为显式默认定义。明确默认的函数应

  • 作为一个特殊的成员函数

  • 具有相同的声明函数类型(除了可能不同的ref限定符,以及在复制构造函数或复制赋值运算符的情况下,参数类型可以是“引用非常量
    T
    ”,其中
    T
    是成员函数类的名称),就好像它是隐式声明的一样

  • 没有默认参数


是的,默认移动构造函数将对其基和成员执行成员移动,因此:

  attribute-specifier-seqopt decl-specifier-seqopt declarator virt-specifier-seqopt = default ;
相当于:

Example(Example&& mE) : a{move(mE.a)}, b{move(mE.b)} { }
我们可以通过查看
12.8
复制和移动类对象一节第13段来了解这一点,该段说(重点放在后面):

默认且未定义为已删除的复制/移动构造函数 是隐式定义的,如果它是odrused(3.2)或显式定义的 在第一次声明后默认。[注:复制/移动 即使省略了实现,构造函数也是隐式定义的 其odr使用(3.2,12.2)。-结束注释][…]

第15段说:

非联合类X的隐式定义的复制/移动构造函数 以成员方式复制/移动其基础和成员。[注: 忽略非静态数据成员的大括号或相等初始值设定项。 另见12.6.2中的示例。-结束注释]顺序 初始化的顺序与基和基的初始化顺序相同 用户定义构造函数中的成员(见12.6.2)。设x为 构造函数的参数,对于移动构造函数,则为 xvalue指的是参数。每个基本或非静态数据成员 以适合其类型的方式复制/移动:

  • 如果成员是数组,则每个元素都直接初始化为对应的子对象x
  • 如果成员m具有右值引用类型T&&,则使用static_cast(x.m)直接初始化它
  • 否则,使用x的相应基或成员直接初始化基或成员
虚拟基类子对象只能由 隐式定义的复制/移动构造函数(见12.6.2)

=默认的
移动构造函数是否等同于成员移动构造函数

更新:嗯,不总是这样。看看这个例子:

Example(Example&& mE)                 = default;

您声明了默认的move构造函数,但会进行复制而不是移动。为什么?因为如果一个类甚至只有一个不可移动的成员,那么显式的默认的move构造函数将被隐式地删除(例如双关语)。因此,当您运行
has_nonmovable d=std::move(c)
时,实际上会调用复制构造函数,因为
has_nonmovable
的移动构造函数被删除(隐式),它只是不存在(即使您通过表达式
显式声明移动构造函数has_nonmovable(has_nonmovable&&)=default

但如果未声明
非移动
的移动构造函数,则移动构造函数将用于
移动
(以及具有移动构造函数的每个成员),复制构造函数将用于
非移动
(以及未定义移动构造函数的每个成员)。请参见示例:

copy

更新:但是如果注释掉
行,则该行具有\u非可移动性(has \u非可移动性&&)=默认值,则复制将用于两个成员:-打印:

movable::move
nonmovable::copy
因此,将
=default
放在任何地方仍然有意义。这并不意味着您的移动表达式将始终移动,但它使这种可能性更高

再更新一次:但如果注释掉
行,则该行具有\u非可移动性(const具有\u非可移动性&)=默认值其中一个,则结果将是:

movable::copy
nonmovable::copy

因此,如果你想知道你的程序中发生了什么,你可以自己做所有事情:叹气:

这可能是@DieterLücking的翻版:显然不是,尽管它的主题类似,一些答案可能涵盖类似的领域。但是,我们不会把关于移动语义的每一个问题都当作彼此的重复来结束。注意,我对这个问题添加了我的答案,因为当时我正在寻找一个来自标准的引用,证明它们是等价的,而被接受的答案并没有这样做。因此,我刚刚找到了引用并添加了我的答案。我还想指出,在您的示例中,默认构造函数没有声明,而析构函数是默认的-请参见引用8.4.2的文档?C++11标准或N3690均未包含8.4.2/1中的文本“且无异常规范”。它们都在8.4.2/2中说:“只有当显式默认函数被隐式声明为
constexpr
时,它才可以被声明为
constexpr
,并且只有当它与隐式声明上的异常规范兼容(15.4)时,它才可能具有显式异常规范。”@Casey Good catch!我引用的是N3242。。。我把我的文件弄混了。。。我更新了我的p
#include <iostream>

struct nonmovable
{
    nonmovable() = default;

    nonmovable(const nonmovable  &) { std::cerr << "nonmovable::copy" << std::endl; }
    //nonmovable(      nonmovable &&) = delete;
};

struct movable
{
    movable() = default;

    movable(const movable  &) { std::cerr << "movable::copy" << std::endl; }
    movable(      movable &&) { std::cerr << "movable::move" << std::endl; }
};

struct has_nonmovable
{
    movable    a;
    nonmovable b;

    has_nonmovable() = default;

    has_nonmovable(const has_nonmovable  &) = default;
    has_nonmovable(      has_nonmovable &&) = default;
};

int main()
{
    has_nonmovable c;
    has_nonmovable d(std::move(c));
}
movable::move
nonmovable::copy
movable::copy
nonmovable::copy
movable::move
nonmovable::copy