Aggregate POD and initialize struct to 0

本文详细解释了C++中的聚合类(Aggregate class)与POD(Plain Old Data)的概念,包括它们的定义、特性及如何初始化。通过具体实例对比了使用memset与构造初始化的不同效果,特别强调了在包含非POD成员时使用memset的危害。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Aggregate class and POD

http://stackoverflow.com/questions/4178175/what-are-aggregates-and-pods-and-how-why-are-they-special/4178176#4178176

An aggregate is an array or a class (clause 9) with no user-declared constructors (12.1), no private or protected non-static data members (clause 11), no base classes (clause 10), and no virtual functions (10.3).

Now let's see how aggregates are special. They, unlike non-aggregate classes, can be initialized with curly braces {}. This initialization syntax is commonly known for arrays, and we just learnt that these are aggregates


POD

An aggregate class is called a POD if it has no user-defined copy-assignment operator and destructor and none of its nonstatic members is a non-POD class, array of non-POD, or a reference.


Initialize struct to 0 

两种 http://stackoverflow.com/questions/1998752/memset-or-value-initialization-to-zero-out-a-struct

1. 

STRUCT theStruct;
memset( &theStruct, 0, sizeof( STRUCT ) );

or

2.STRUCT theStruct ={};


具体的例子 

struct POD_OnlyStruct
{
    int a;
    char b;
};

POD_OnlyStruct t = {};  // OK

POD_OnlyStruct t;
memset(&t, 0, sizeof t);  // OK as well

In this case writing a POD_OnlyStruct t = {} or POD_OnlyStruct t; memset(&t, 0, sizeof t)doesn't make much difference, as the only difference we have here is the alignment bytes being set to zero-value in case of memset used. Since you don't have access to those bytes normally, there's no difference for you.

On the other hand, since you've tagged your question as C++, let's try another example, with member types different from POD:

struct TestStruct
{
    int a;
    std::string b;
};

TestStruct t = {};  // OK

{
    TestStruct t1;
    memset(&t1, 0, sizeof t1);  // ruins member 'b' of our struct
}  // Application crashes here

In this case using an expression like TestStruct t = {} is good, and using a memset on it will lead to crash. Here's what happens if you use memset - an object of type TestStruct is created, thus creating an object of type std::string, since it's a member of our structure. Next, memsetsets the memory where the object b was located to certain value, say zero. Now, once our TestStruct object goes out of scope, it is going to be destroyed and when the turn comes to it's member std::string b you'll see a crash, as all of that object's internal structures were ruined by the memset.

作者:一根筋的傻瓜
链接:https://www.zhihu.com/question/36379130/answer/69853366
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

POD,全称plain old data,plain代表它是一个普通类型,old代表它可以与c兼容,可以使用比如memcpy()这类c中最原始函数进行操作。C++11中把POD分为了两个基本概念的集合,即:平凡的(trival)和标准布局的(standard layout)。
  1. 首先是平凡的(trival)定义,通常一个平凡的类或者结构体需要满足以下定义:
  • 拥有平凡的默认构造函数和析构函数默认的意思就是由编译器为我们自动生成的,不许是我们自己定义的,但是由于c++11提供了default,也可以是自己定义的加=default,比如
struct Trival{
Trival(){}=default;
}
就是满足这个要求的,而
struct noTrival{
noTrival(){};
}
就不满足这个要求(哪怕我们定义的构造函数体里面啥都没有)。这个要求对于带参的构造函数没有束缚。你可以自定义带参的构造函数只要不是默认的就好
  • 拥有平凡的拷贝构造函数和移动构造函数。默认的意思同上,也可以使用=default。
  • 拥有平凡的拷贝赋值操作符和移动赋值操作符。
  • 不能包含虚函数和虚基类。

2.接下来是标准布局的定义:standard layout
  • 所有非静态成员拥有相同的访问级别,(访问级别就是public,private,protected),
struct t1{
private :
int a;
public:
int b;
}就不满足标准布局,因为a,b访问级别不同
  • 在类和结构体继承时需要满足以下两个情况之一:
    • 派生类中有非静态类,那么这个派生类只能有且只有一个仅包含了静态成员的基类。
    • 基类有非静态成员,那么派生类中不允许有非静态成员。
这两句话看着挺绕口,其实就是在说明一个事实,关于非静态数据的事实,派生类中有非 静态的数据那么它的基类只能是只有静态的,而且基类只能有一个。如果基类有非静态的, 那么派生类就不能有非静态的。有种跷跷板的感觉,非静态的对面坐着的是静态,父子类就 是坐在跷跷板的两端这种对应关系。)
  • 类中第一个非静态类型与基类不是同一个类型。比如
struct A:B{
B b;
int c;
}就不符合这个条件。因为A中第一个成员是基类B类型的。

  • 没有虚类和虚基类(与trival中重复)
  • 所有非静态数据成员都符合标准布局的要求,这其实就是一个递归的定义。
所以在C++11中,POD就是满足平凡的(trival)和标准布局(standard layout)这两个方面。可以使用<type_traits>中的is_pod<T>::value判断T是不是POD类型的。

说了这么多,那么为什么我们需要POD这种条件满足的数据呢?

  1. 可以使用字节赋值,比如memset,memcpy操作
  2. 对C内存布局兼容。
  3. 保证了静态初始化的安全有效。

同时 我在自己的code里面也遇到

Don't use malloc in C++ (unless you absolutely know what youre doing)  

https://stackoverflow.com/questions/30579430/access-violation-writing-location-0xcdcdcdcd

ptrStack stack = (ptrStack)malloc(sizeof(Stack));

The Stack structure contains an object of type string. The string constructor must be called before you can use the string. If you allocate memory using the C++ new operator, then the constructor is automatically called, and the string is properly initialized.

But if you allocate memory using the C malloc function, then the string constructor is not called. The 0xCDCDCDCD comes from an uninitialized pointer in the string object that should have been initialized by the constructor (but wasn't because the constructor was not called).


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值