tucuxi
tucuxi

Reputation: 17945

initialization of structs/classes without constructors in stack vs heap

I would like to know the rule for zeroing-out structs (or classes) that have no default constructor in C++.

In particular, it seems that if stored in the stack (say, as a local variable) they are uninitialized, but if allocated on the heap, they are zero-initialized (tested with GCC 4.9.1). Is this guaranteed to be portable?

Example program:

#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;
}

Edited: removed an "or should I just use a constructor" in the bolded part; because what made me ask is that I want to know if it is guaranteed behaviour or not - we can all agree that readable code is better of with explicit constructors.

Upvotes: 2

Views: 1035

Answers (3)

timato
timato

Reputation: 182

As long as you don't have any constructors, all members are public, and there is no inheritance involved, your struct/class is likely an aggregate.

To get portable zero-initialization, simply use X x = {}; which performs zero intialization.

Here is the standard quote about aggregates (8.5.1):

An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no brace-or-equal-initializers for non-static data members (9.2), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).

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

Upvotes: 0

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385194

It's not the dynamic allocation that's zero-initialising your struct members; it's your syntax:

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

If you want it guaranteed, just keep writing that. :)

An alternative, which meshes well with the automatic-storage-duration equivalent, is to use the newer {} syntax:

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

And objects with static storage duration are always pre-zero-initialised no matter what, so you're covered there by default.

Upvotes: 5

Puppy
Puppy

Reputation: 146940

Always use a constructor if you want to give your class's members particular values. That's literally what constructors are for. The only time you don't need to write a constructor that sets the values you want is if the language pre-provides one for you like copy constructor. Default constructor is not on this list for int and other such types so you have to add a constructor to your own type that sets them appropriately.

Upvotes: 3

Related Questions