Aggregate POD and initialize struct to 0

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).


在数据分析中,当我们提到"numeric types to aggregate",通常是指在处理数值型数据时,常用的聚合操作。这些操作帮助我们从大量数据中提炼出有意义的信息,例如: 1. **求和(Sum)**:对数值类型的字段求和,用于计算总数或总收入等。 ```python df['column_name'].sum() ``` 2. **平均值(Average/Mean)**:计算数值列的平均值,反映数据集中值的平均水平。 ```python df['column_name'].mean() ``` 3. **最大值(Max)**:找出数值范围内最大的值,常用于找出最高值或极值。 ```python df['column_name'].max() ``` 4. **最小值(Min)**:找出数值范围内的最小值。 ```python df['column_name'].min() ``` 5. **计数(Count)**:计算非空值的数量,用于了解观测次数。 ```python df['column_name'].count() ``` 6. **标准差(Standard Deviation)**:衡量数值分布的离散程度。 ```python df['column_name'].std() ``` 7. **方差(Variance)**:类似于标准差,但不除以数量,反映了数据点相对于均值的散布。 ```python df['column_name'].var() ``` 8. **百分位数(Percentiles)**:将数值划分为特定的区间,如第25分位数(Q1)、第50分位数(中位数)和第75分位数(Q3)。 ```python df['column_name'].quantile([0.25, 0.5, 0.75]) ``` 这些聚合函数可以帮助我们在大数据集中进行描述性统计分析,识别模式、异常值以及发现潜在的业务洞察。在使用这些函数之前,确保所选列的数据类型确实是数值型(如int, float, decimal等)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值