复制构造函数

来自cppreference.com
< cpp‎ | language

T 的复制构造函数是非模板构造函数,其首参数为 T&const T&volatile T&const volatile T& ,而且要么没有其他参数,要么剩余参数均有默认值。

目录

[编辑] 语法

class_name ( const class_name & ) (1)
class_name ( const class_name & ) = default; (2)
class_name ( const class_name & ) = delete; (3)

[编辑] 解释

  1. 复制构造函数的典型声明。
  2. 强制编译器生成复制构造函数。
  3. 阻止生成复制构造函数。

凡在对象从同类型的另一对象(以直接初始化复制初始化初始化时,调用复制构造函数(除非重载决议选择更好的匹配或调用被消除),这包含

  • 初始化: T a = b;T a(b); ,其中 b 有类型 T
  • 函数参数传递: f(a); ,其中 a 有类型 TfRet f(T t)
  • 函数返回:在如 T f() 的函数内部的 return a; ,其中 a 有类型 T ,它无移动构造函数。

[编辑] 隐式声明的复制构造函数

若不对类类型( structclassunion )提供用户定义的复制构造函数,则编译器始终会声明复制构造函数,作为其类的非 explicitinline public 成员。此隐式声明的复制构造函数拥有形式 T::T(const T&) ,若下列所有为真:

  • T 的每个直接与虚基类 B 拥有复制构造函数,其参数是 Bconst B&const volatile B&
  • T 的每个类类型或类类型数组的非静态数据成员 M 拥有复制构造函数,其参数是 Mconst M&const volatile M&

否则隐式声明的复制构造函数是 T::T(T&) 。(注意因为这些规则,隐式声明的复制构造函数不能绑定到 volatile 左值参数)。

类可拥有多个复制构造函数,如 T::T(const T&)T::T(T&) 。若某个用户定义复制构造函数,则用户仍可用关键词 default 强迫编译器生成隐式声明的复制构造函数。

(C++11 起)

隐式声明(或于其首个声明设为默认)的复制构造函数拥有描述于动态异常规定 (C++17 前)异常规定 (C++17 起)的异常规定。

[编辑] 被删除的隐式声明的复制构造函数

若任何下列者为真,则不定义类 T 的隐式声明的复制构造函数: (C++11 前)
若任何下列条件为真,则定义 T 的隐式声明的复制构造函数为被删除 (C++11 起)
  • T 有不能复制的非静态数据成员(有被删除、不可访问或有歧义的复制构造函数);
  • T 有不能复制的直接或虚基类(有被删除、不可访问或有歧义的复制构造函数);
  • T 有带被删除或不可访问的析构函数的直接或虚基类;
  • T 有用户定义的移动构造函数或移动赋值运算符;
  • T 是类联合类并拥有带非平凡复制构造函数的变体成员;
  • T 拥有右值引用类型的数据成员。
(C++11 起)

[编辑] 平凡复制构造函数

若下列全为真,则类 T 的复制构造函数为平凡:

  • 它不是用户提供的(即它是隐式定义或设为默认的),且若它被设为默认,则其签名同隐式定义者 (C++14 前);
  • T 无虚成员函数;
  • T 无虚基类;
  • T 每个基类选择的复制构造函数是平凡的;
  • 为每个 T 类类型(或类类型数组)非静态成员选择的复制构造函数是平凡的;

平凡的复制构造函数创建参数的对象表示的逐位复制,而且不进行任何其他动作。可平凡复制 (TriviallyCopyable) 对象可手工从其对象表示复制,例如用 std::memmove 。所有与 C 语言兼容的数据类型( POD 类型)均为可平凡复制。

[编辑] 隐式定义的复制构造函数

若隐式声明的复制构造函数既非被删除亦非平凡,则若它被 odr 使用,则为编译器所定义(即生成并编译函数体)。对于 union 类型,隐式定义的复制构造函数复制对象表示(如同以 std::memmove )。对于非联合类类型( classstruct ),构造函数用直接初始化,以其初始化顺序,进行对象基类和非静态成员的逐成员复制。

隐式定义的复制构造函数的生成为过时,若 T 拥有用户定义析构函数或用户定义复制赋值运算符。

(C++11 起)

[编辑] 注意

许多情况下,复制构造函数会被优化掉,即使它们生成可观测副效应,见复制消除

[编辑] 示例

struct A
{
    int n;
    A(int n = 1) : n(n) { }
    A(const A& a) : n(a.n) { } // 用户定义复制构造函数
};
 
struct B : A
{
    // 隐式默认构造函数 B::B()
    // 隐式复制构造函数 B::B(const B&)
};
 
struct C : B
{
     C() : B() { }
 private:
     C(const C&); // 不可复制, C++98 风格
};
 
int main()
{
    A a1(7);
    A a2(a1); // 调用复制构造函数
    B b;
    B b2 = b;
    A a3 = b; // 转换到 A& 并调用复制构造函数
    volatile A va(10);
    // A a4 = va; // 编译错误
 
    C c;
    // C c2 = c; // 编译错误
}

[编辑] 缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR 应用于 出版时的行为 正确行为
CWG 2171 C++14 X(X&) = default 非平凡 使它平凡
CWG 496 C++11 有 volatile 成员的结构体是可平凡复制的 volatile 成员令复制非平凡
CWG 2094 C++14 vafter=volatile 成员令复制非平凡 有 volatile 成员的结构体是可平凡复制的