Trivial 类型
上面提到的第一个特性Trivial:trivial类型支持静态初始化。如果一个类型是拷贝不变的(trivially copyable),使用memcpy这种方式把它的数据从一个地方拷贝出来会得到相同的结果。
C++标准把trivial类型定义如下:
一个拷贝不变(trivially copyable)类型是指:
-
没有non-trivial 的复制构造函数
-
没有non-trivial的转移构造函数
- 没有non-trivial的赋值操作符
-
没有non-trivial的转移赋值操作符
- 有一个trivial的析构函数
一个trivial class类型是指有一个trivial类型的默认构造函数,而且是拷贝不变的(trivially copyable)的class。(特别注意,拷贝不变类型和trivial类型都不能有虚函数和虚基类)。
那么,这么trivial和non-trivial类型到底是什么呢?
Class X复制或转移构造函数是trivial类型的,如果他不是用户提供的,而且
- Class X没有任何虚函数和虚基类,而且
- 用于复制或转移直接基类的构造函数是trivial类型的,而且
- 复制或转移构造函数选择复制或转移的X内部的每一个非静态数据成员(或数组)必须是trivial类型的
否则,复制或转移构造函数就是non-trivial类型的
从根本上也就是说复制或转移构造函数是trivial类型的只要他不是用户提供的、类内部没有虚函数,而且这个规则要递归地适用于所有数据成员类型和基类。
Trivial类型赋值或转移操作符的定义类似,把构造函数替换为赋值操作符就可以了。
Trivial类型的析构函数也有类似的定义,不过要加一条限制,就是不能为虚函数。
Trivial类型的默认构造函数也需要加一条限制:上面我们已经看到了,不能拥有{ }或=初始化的(brace-or-equal-initializers)非静态数据成员。
这里有个几个例子能让你彻底明白每个类型:
// empty classes are trivial
struct Trivial1 {};
// all special members are implicit
struct Trivial2 {
int x;
};
struct Trivial3 : Trivial2 { // base class is trivial
Trivial3() = default; // not a user-provided ctor
int y;
};
struct Trivial4 {
public:
int a;
private: // no restrictions on access modifiers
int b;
};
struct Trivial5 {
Trivial1 a;
Trivial2 b;
Trivial3 c;
Trivial4 d;
};
struct Trivial6 {
Trivial2 a[23];
};
struct Trivial7 {
Trivial6 c;
void f(); // it's okay to have non-virtual functions
};
struct Trivial8 {
int x;
static NonTrivial1 y; // no restrictions on static members
}
struct Trivial9 {
Trivial9() = default; // not user-provided
// a regular constructor is okay because we still have default ctor
Trivial9(int x) : x(x) {};
int x;
}
struct NonTrivial1 : Trivial 3 {
virtual f(); // virtual members make non-trivial ctors
}
struct NonTrivial2 {
NonTrivial2() : z(42) {} // user-provided ctor
int z;
}
struct NonTrivial3 {
NonTrivial3(); // user-provided ctor
int w;
}
NonTrivial3::NonTrivial3() = default; // defaulted but not on first declaration
// still counts as user-provided
struct NonTrivial5 {
virtual ~NonTrivial5(); // virtual destructors are not trivial
};