在线文档教程
C++
语言 | Language

Move constructors

移动构造器

类的移动构造函数T是一个非模板构造函数,其第一个参数是T&&,,,const T&&,,,volatile T&&,或const volatile T&&,或者没有其他参数,或者其余的参数都有默认值。

句法

class_name ( class_name && )(1)(since C++11)
class_name ( class_name && ) = default;(2)(since C++11)
class_name ( class_name && ) = delete;(3)(since C++11)

解释

  • 移动构造函数的典型声明。

  • 强制编译器生成移动构造函数。

  • 避免隐式移动构造函数。

选择的任何时候都会调用移动构造函数。过载分辨率,这通常发生在初始化28%直接初始化或复制初始化29%r值%28xvalue或prvalue%29%28,直到C++17%29xvalue%28,因为C++17%29具有相同类型,包括。

  • 初始化:T a = std::move(b或T a(std::move(b),其中b是类型的T;

  • 函数参数传递:f(std::move(a),在哪里a是型的T和fvoid f(T t);

  • 函数返回:return a;在诸如T f(),在哪里a是类型的T它有一个移动构造函数。

移动构造函数通常会“窃取”参数%28所持有的资源。指向动态分配的对象、文件描述符、TCP套接字、I/O流、正在运行的线程等的指针,而不是复制它们,并将参数保留在某种有效但不确定的状态。例如,从std::string或者从一个std::vector可能会导致该论点被保留为空。但是,不应依赖这种行为。对于某些类型,例如std::unique_ptr,移出状态被完全指定。

隐式声明的移动构造函数

如果没有为类类型%28提供用户定义的移动构造函数struct,,,class,或union%29,以下所有情况都是正确的:

  • 没有用户声明的副本构造函数;

  • 没有用户声明的副本分配操作符;

  • 没有用户声明的移动分配操作符;

  • 没有用户声明的析构函数;

the implicitly-declared move constructor is not defined as deleted due to conditions detailed in the next section,(until C++14)

  • 隐式声明的移动构造函数未定义为删除由于下一节的详细情况,%28直到C++14%29然后,编译器将将移动构造函数声明为非-显式inline public具有签名的类的成员。T::T(T&&)...一个类可以有多个移动构造函数,例如两个T::T(const T&&)T::T(T&&)如果存在某些用户定义的移动构造函数,则用户仍然可能强制生成带有关键字的隐式声明的move构造函数。default...隐式声明的%28或默认的第一次声明%29移动构造函数具有异常规范,如动态异常规范%28直到C++17%29异常规格%28自C++17%29。删除隐式声明的移动构造函数类的隐式声明或默认移动构造函数。T定义为删除下列任何一项都是正确的:

  • T不能移动%28的非静态数据成员是否已删除、不可访问或模棱两可的移动构造函数%29;

  • T具有无法移动的直接或虚拟基类%28已删除、不可访问或模糊移动构造函数%29;

  • T具有直接或虚拟基类的已删除或不可访问的析构函数;

  • T是一个联合并且有一个具有非平凡复制构造函数的变体成员;

T has a non-static data member or a direct or virtual base without a move constructor that is not trivially copyable.(until C++14)

  • T具有非静态数据成员或直接或虚拟基,而没有移动构造函数,这些构造函数都是不可复制的。%28直到C++14%29已删除的隐式声明的移动构造函数被重载解析%28忽略,否则将阻止rvalue%29中的复制初始化。%28自C++14%29平凡移动构造函数类的移动构造函数T如果以下所有内容都为真,则是微不足道的:

  • 它不是用户提供的%28,它是隐式定义的或默认的%29;

  • T没有虚拟成员功能;

  • T没有虚拟基类;

  • 的每个直接基选择的移动构造函数。T是微不足道的;

  • 为每个非静态类类型%28或类类型%29成员的数组选择的移动构造函数。T是微不足道的;

T has no non-static data members of volatile-qualified type.(since C++14)

  • T的非静态数据成员。易挥发-合格类型。

%28自C++14%29

一个普通的移动构造函数是一个构造函数,它执行与普通副本构造函数相同的操作,也就是说,使对象表示的副本就像std::memmove所有与C语言%28POD类型%29兼容的数据类型都是可移动的。

隐式定义的移动构造函数

如果隐式声明的移动构造函数既不删除也不简单,则定义为%28,即编译器生成和编译函数体%29ODR-使用.为union类型时,隐式定义的移动构造函数通过以下方式复制对象表示%28std::memmove29%。对于非工会类类型%28classstruct%29,移动构造函数按照初始化顺序对对象%27s基和非静态成员执行完全成员级移动,使用x值争论。

注记

为了使强异常保证成为可能,用户定义的移动构造函数不应抛出异常。例如,std::vector倚靠std::move_if_noexcept在需要重新定位元素时在移动和复制之间进行选择。

如果同时提供了复制和移动构造函数,则如果参数为r值%28或aprvalue例如无名的临时的或x值如…的结果std::move%29,如果参数是洛值%28命名对象或返回lvalue引用%29的函数/运算符。如果只提供了复制构造函数,所有参数类别都会选择它%28,只要它引用Const,因为rvalue可以绑定到Const引用%29,这使得在移动不可用时复制移动回退。

在许多情况下,即使移动构造函数会产生明显的副作用,也可以优化它们,请参见复制省略...

当构造函数以rvalue引用作为参数时,它被称为%27移动构造函数%27。它没有义务移动任何东西,类不需要有要移动的资源,%27 Move构造函数%(5月27日)不能像允许的%28那样移动资源,但是在参数为Const值引用%28 const T&&%29的情况下,可能不合理。

二次

#include <string> #include <iostream> #include <iomanip> #include <utility> struct A { std::string s; A() : s("test") { } A(const A& o) : s(o.s) { std::cout << "move failed!\n"; } A(A&& o) noexcept : s(std::move(o.s)) { } }; A f(A a) { return a; } struct B : A { std::string s2; int n; // implicit move constructor B::(B&&) // calls A's move constructor // calls s2's move constructor // and makes a bitwise copy of n }; struct C : B { ~C() { } // destructor prevents implicit move ctor C::(C&&) }; struct D : B { D() { } ~D() { } // destructor would prevent implicit move ctor D::(D&&) D(D&&) = default; // force a move ctor anyway }; int main() { std::cout << "Trying to move A\n"; A a1 = f(A() // move-construct from rvalue temporary A a2 = std::move(a1 // move-construct from xvalue std::cout << "Trying to move B\n"; B b1; std::cout << "Before move, b1.s = " << std::quoted(b1.s) << "\n"; B b2 = std::move(b1 // calls implicit move ctor std::cout << "After move, b1.s = " << std::quoted(b1.s) << "\n"; std::cout << "Trying to move C\n"; C c1; C c2 = std::move(c1 // calls the copy constructor std::cout << "Trying to move D\n"; D d1; D d2 = std::move(d1 }

二次

产出:

二次

Trying to move A Trying to move B Before move, b1.s = "test" After move, b1.s = "" Trying to move C move failed! Trying to move D

二次

© cppreference.com

在CreativeCommonsAttribution下授权-ShareAlike未移植许可v3.0。

http://en.cppreference.com/w/cpp/language/move[医]构造器