在堆栈与堆中没有构造函数的结构/类的初始化

时间:2015-05-06 13:05:22

标签: c++ struct initialization

我想知道在C ++中没有默认构造函数的清零结构(或类)的规则。

特别是,如果存储在堆栈中(例如,作为局部变量),它们似乎是未初始化的,但如果在堆上分配,它们将被初始化为零(使用GCC 4.9.1进行测试)。 这是否可以保证便携

示例程序:

#include <iostream>
#include <map>
using namespace std;

struct X {
    int i, j, k;
    void show() { cout << i << " " << j << " " << k << endl; }
};

int fib(int i) {
    return (i > 1) ? fib(i-1) + fib(i-2) : 1;
}

int main() {
    map<int, X> m;            
    fib(10);                  // fills the stack with cruft
    X x1;                     // local
    X &x2 = m[1];             // heap-allocated within map
    X *x3 = new X();          // explicitly heap-allocated
    x1.show();  // --> outputs whatever was on the heap in those positions
    x2.show();  // --> outputs 0 0 0 
    x3->show(); // --> outputs 0 0 0     
    return 0;
}

编辑:在粗体部分删除了“或者我应该只使用构造函数”;因为让我问的是,我想知道它是否有保证行为 - 我们都同意可读代码在显式构造函数方面更好。

3 个答案:

答案 0 :(得分:5)

不是动态分配对您的struct成员进行零初始化;这是你的语法:

X* ptr = new X();
//            ^^
// 
// as opposed to just:
X* ptr = new X;

如果你想保证,那就继续写下来吧。 :)

与自动存储持续时间相当的网格很好的替代方法是使用较新的{}语法:

X* ptr = new X{};   // dynamic
X  obj{};           // automatic

具有静态存储持续时间的对象无论如何都始终为零初始化,因此默认情况下您将被覆盖。

答案 1 :(得分:3)

如果您想为您的班级成员提供特定值,请始终使用构造函数。这实际上是构造函数的用途。你唯一一次不需要编写一个设置你想要的值的构造函数就是语言预先为你提供一个像复制构造函数。默认构造函数不在 <ListView ItemsSource="{Binding machines}> <ListView.View> <GridView> <GridViewColumn DisplayMemberBinding="{Binding producer.name, IsAsync=True}" Width="Auto"> </GridViewColumn> <GridViewColumn DisplayMemberBinding="{Binding machineType.name, IsAsync=true}" Width="Auto"> </GridViewColumn> etc... </GridView> </ListView.View> </ListView> 和其他此类类型的此列表中,因此您必须将构造函数添加到您自己的类型中,以便适当地设置它们。

答案 2 :(得分:0)

只要你没有任何构造函数,所有成员都是公共的,并且没有涉及继承,你的struct / class可能是聚合。

要获得便携式零初始化,只需使用执行零初始化的X x = {};

以下是关于聚合的标准报价(8.5.1):

  

聚合是一个没有用户提供的数组或类(第9条)   构造函数(12.1),非静态的支撑或等于初始化器   数据成员(9.2),没有私有或受保护的非静态数据成员   (第11条),没有基类(第10条),也没有虚函数   (10.3)。

参考:Why can I not brace initialize a struct derived from another struct?