首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

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)

解释

  1. 移动构造函数的典型声明。
  1. 强制编译器生成移动构造函数。
  1. 避免隐式移动构造函数。

选择的任何时候都会调用移动构造函数。过载分辨率,这通常发生在初始化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是类型的Tfvoid 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的情况下,可能不合理。

二次

代码语言:javascript
复制
#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);
}

二次

产出:

二次

代码语言:javascript
复制
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

二次

代码语言:txt
复制
 ? cppreference.com

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

扫码关注腾讯云开发者

领取腾讯云代金券

http://www.vxiaotou.com