class NotAggregate1
{
virtual void f() {} //remember? no virtual functions
};
class NotAggregate2
{
int x; //x is private by default and non-static
};
class NotAggregate3
{
public:
NotAggregate3(int) {} //oops, user-defined constructor
};
class Aggregate1
{
public:
NotAggregate1 member1; //ok, public member
Aggregate1& operator=(Aggregate1 const & rhs) {/* */} //ok, copy-assignment
private:
void f() {} // ok, just a private function
};
class A
{
public:
A(int) {} //no default constructor
};
class B
{
public:
B() {} //default constructor available
};
int main()
{
A a1[3] = {A(2), A(1), A(14)}; //OK n == m
A a2[3] = {A(2)}; //ERROR A has no default constructor. Unable to value-initialize a2[1] and a2[2]
B b1[3] = {B()}; //OK b1[1] and b1[2] are value initialized, in this case with the default-ctor
int Array1[1000] = {0}; //All elements are initialized with 0;
int Array2[1000] = {1}; //Attention: only the first element is 1, the rest are 0;
bool Array3[1000] = {}; //the braces can be empty too. All elements initialized with false
int Array4[1000]; //no initializer. This is different from an empty {} initializer in that
//the elements in this case are not value-initialized, but have indeterminate values
//(unless, of course, Array4 is a global array)
int array[2] = {1, 2, 3, 4}; //ERROR, too many initializers
}
struct X
{
int i1;
int i2;
};
struct Y
{
char c;
X x;
int i[2];
float f;
protected:
static double d;
private:
void g(){}
};
Y y = {'a', {10, 20}, {20, 30}};
如果一个聚合类被称为POD
它没有用户定义的拷贝赋值
运算符和析构函数都没有
它的非静态成员是非pod
类、非pod数组或
参考。< / p >
这个定义意味着什么?(我提到过圆荚体代表普通旧数据 .吗?)
所有POD类都是聚合,或者,换句话说,如果一个类不是聚合,那么它肯定不是POD
类,就像结构体一样,可以是pod,尽管这两种情况的标准术语都是POD-struct
就像在聚合的情况下一样,类有什么静态成员并不重要
例子:
struct POD
{
int x;
char y;
void f() {} //no harm if there's a function
static std::vector<char> v; //static members do not matter
};
struct AggregateButNotPOD1
{
int x;
~AggregateButNotPOD1() {} //user-defined destructor
};
struct AggregateButNotPOD2
{
AggregateButNotPOD1 arrOfNonPod[3]; //array of non-POD class
};
#define N sizeof(T)
char buf[N];
T obj; // obj initialized to its original value
memcpy(buf, &obj, N); // between these two calls to memcpy,
// obj might be modified
memcpy(&obj, buf, N); // at this point, each subobject of obj of scalar type
// holds its original value
< p > goto语句。正如你所知道的,通过goto从某个变量尚未在作用域中的点跳转到它已经在作用域中的点是非法的(编译器应该发出一个错误)。此限制仅适用于非pod类型的变量。在下面的例子中,f()是格式错误的,而g()是格式良好的。请注意,微软的编译器对这条规则太自由了——它只是在两种情况下发出警告。
int f()
{
struct NonPOD {NonPOD() {}};
goto label;
NonPOD x;
label:
return 0;
}
int g()
{
struct POD {int i; char c;};
goto label;
POD x;
label:
return 0;
}
struct NotAggregate {
int x = 5; // valid in C++11
std::vector<int> s{1,2,3}; // also valid
};
使用这个特性使类不再是一个聚合,因为它基本上等同于提供自己的缺省构造函数。
所以,什么是总量没有太大的变化。它仍然是相同的基本思想,适应新的特点。
POD 呢?
犯罪现场发生了很多变化。在这个新标准中,以前关于 POD 的许多规则都被放宽了,标准中提供定义的方式也发生了根本性的变化。
POD 的想法基本上是捕获两个截然不同的属性:
它支持静态初始化,并且
在 C + + 中编译 POD 可以得到与在 C 中编译的结构相同的内存布局。
因此,定义被分成两个不同的概念: 微不足道类和 标准布局类,因为它们比 POD 更有用。该标准现在很少使用术语 POD,倾向于更具体的 微不足道和 标准布局概念。
新的定义基本上是说 POD 是一个既简单又具有标准布局的类,并且这个属性必须递归地保存所有非静态数据成员:
POD 结构是一个非联合类,它既是一个普通类,也是一个标准布局类,
并且没有类型为 non-POD struct、 non-POD union (或这类型的数组)的非静态数据成员。
类似地,POD 联合是一个联合,它既是一个普通类,又是一个标准布局类,并且具有
没有非 POD 结构类型的非静态数据成员、非 POD 联合(或此类型的数组)。
POD 类是一个既可以是 POD 结构也可以是 POD 联合的类。
// 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 : Trivial3 {
virtual void 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
};
标准布局
标准布局 是第二个属性。标准提到这些对于与其他语言进行通信非常有用,这是因为标准布局类具有与等效的 C 结构或联合相同的内存布局。
这是必须为成员和所有基类递归保存的另一个属性。和往常一样,不允许使用虚函数或虚基类。这将使布局与 C 不兼容。
// empty classes have standard-layout
struct StandardLayout1 {};
struct StandardLayout2 {
int x;
};
struct StandardLayout3 {
private: // both are private, so it's ok
int x;
int y;
};
struct StandardLayout4 : StandardLayout1 {
int x;
int y;
void f(); // perfectly fine to have non-virtual functions
};
struct StandardLayout5 : StandardLayout1 {
int x;
StandardLayout1 y; // can have members of base type if they're not the first
};
struct StandardLayout6 : StandardLayout1, StandardLayout5 {
// can use multiple inheritance as long only
// one class in the hierarchy has non-static data members
};
struct StandardLayout7 {
int x;
int y;
StandardLayout7(int x, int y) : x(x), y(y) {} // user-provided ctors are ok
};
struct StandardLayout8 {
public:
StandardLayout8(int x) : x(x) {} // user-provided ctors are ok
// ok to have non-static data members and other members with different access
private:
int x;
};
struct StandardLayout9 {
int x;
static NonStandardLayout1 y; // no restrictions on static members
};
struct NonStandardLayout1 {
virtual f(); // cannot have virtual functions
};
struct NonStandardLayout2 {
NonStandardLayout1 X; // has non-standard-layout member
};
struct NonStandardLayout3 : StandardLayout1 {
StandardLayout1 x; // first member cannot be of the same type as base
};
struct NonStandardLayout4 : StandardLayout3 {
int z; // more than one class has non-static data members
};
struct NonStandardLayout5 : NonStandardLayout3 {}; // has a non-standard-layout base class
结论
有了这些新规则,现在可以有更多的 POD 类型。而且,即使类型不是 POD,我们也可以单独利用一些 POD 属性(如果它只是平凡的或标准布局的属性之一)。
POD struct110是一个非联合类,它既是一个普通类,又是一个
标准布局类,并且没有类型为
非 POD 结构,非 POD 联合(或此类型的数组)
POD 联合是一个联合,它既是一个普通类,又是一个
类,并且没有类型为
非 POD 结构,非 POD 联合(或此类型的数组)
一个既是 POD 结构又是 POD 联合的类。
这和 C + + 11的措辞是一样的。
标准-C + + 14的布局更改
正如评论中指出的那样,豆荚依赖于 标准布局的定义,而且对于 C + + 14来说确实发生了变化,但这是通过事后应用于 C + + 14的缺陷报告实现的。
在 C + + 14中,对于一个非平凡的类,该类不能有任何非平凡的复制/移动构造函数/赋值操作符。然而,作为默认构造函数/运算符的隐式 声明可能是非平凡的,而作为删除的 定义可能是非平凡的,因为,例如,类包含一个类类型的子对象,不能被复制/移动。这种非平凡的、定义为删除的构造函数/运算符的存在将导致整个类非平凡。析构函数也存在类似的问题。C + + 17澄清了这样的构造函数/运算符的存在并不会导致类是非平凡的可复制类,因此是非平凡的,并且一个非平凡的可复制类必须有一个平凡的、不删除的析构函数。DR1734,DR1928
C + + 14允许一个普通的可复制类(因此是一个普通类)将每个复制/移动构造函数/赋值操作符声明为删除。如果这样的类也是标准的布局,但是,它可以合法复制/移动与 std::memcpy。这是一个语义上的矛盾,因为,通过定义为删除所有构造函数/赋值操作符,类的创建者显然意图类不能被复制/移动,但类仍然符合一个微不足道的可复制类的定义。因此,在 C + + 17中,我们有了一个新的子句,声明可复制类必须至少有一个不重要的、不删除的(尽管不一定是公开可访问的)拷贝/移动构造函数/赋值操作符。参见 N4148,DR1734
第三个技术变化与默认构造函数的类似问题有关。在 C + + 14中,一个类可以有一些微不足道的默认构造函数,这些构造函数被隐式定义为已删除,但仍然是一个微不足道的类。新的定义澄清了一个普通类必须至少有一个普通的、未删除的缺省构造函数。参见 DR1496
类 S 是一个标准布局类,如果它:
ー没有类型非标准布局类(或此类型的数组)或引用的非静态数据成员,
ー没有虚函数和虚基类,
ー对所有非静态数据成员具有相同的访问控制,
ー没有非标准布局的基类,
ー最多只有一个给定类型的基类子对象,
ー拥有类中的所有非静态数据成员和位字段及其首先在同一个类中声明的基类,以及
ー没有类型集 M (S)的元素(下面定义)作为基类
M (X)的定义如下:
ー如果 X 是没有(可能继承的)非静态数据成员的非联合类型,则集合 M (X)为空。
ーー如果 X 是一个非联合类型,其第一个非静态数据成员的类型为 X0(其中所述成员可能是匿名联合) ,则集合 M (X)由 X0和 M (X0)的元素组成。
ー如果 X 是并集类型,则集合 M (X)是所有 M (UI)的并集和包含所有 UI 的集合,其中每个 UI 是 X 的第 i 个非静态数据成员的类型。
ー如果 X 是元素类型为 Xe 的数组类型,则集合 M (X)由 Xe 和 M (Xe)的元素组成。
ー如果 X 是非类、非数组类型,则集合 M (X)为空。
[注意: M (X)是所有非基类子对象的类型集合,在标准布局类中保证 X 中的偏移量为零。ー结束注意]
[例子:
struct B { int i; }; // standard-layout class
struct C : B { }; // standard-layout class
struct D : C { }; // standard-layout class
struct E : D { char : 4; }; // not a standard-layout class
struct Q {};
struct S : Q { };
struct T : Q { };
struct U : S, T { }; // not a standard-layout class