您的位置:首页 > 其它

Aggregate POD and initialize struct to 0

2016-03-02 12:01 260 查看
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, 
memset
sets
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)。
首先是平凡的(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这种条件满足的数据呢?

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

同时 我在自己的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).
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: