-2

The code:

#include <iostream>

class cMapRender
{
public:
unsigned int m_rightMargin;
unsigned int m_bottomMargin;
unsigned int m_x;
unsigned int test;
unsigned int m_y;
unsigned int m_width;
unsigned int m_height;
};

int main(int argc, char **argv)
{
cMapRender mapRender;

std::cout << mapRender.m_x << std::endl; //gives random values (like 45321231)
std::cout << mapRender.m_height << std::endl;
std::cout << mapRender.m_width << std::endl;

return 0;
}

How is this possible that when I run it through debugger (or just cout some values), some members are 0 and some are random value? I think that pod members should be 0-initialized.

I use g++ 4.7 on linux. When I ran it on ideone.com, on gcc 4.7 I got this bug too. However, on ideone.com gcc 4.3 every member was 0-initialized!

What's going on here, why members aren't always 0-initialized? I read that C standard says that pod should be always 0 initialized.

user1873947
  • 1,781
  • 3
  • 27
  • 47
  • 3
    You said it yourself. They're uninitialized. – chris Jun 24 '13 at 13:14
  • @chris but why? aren't they on stack? – user1873947 Jun 24 '13 at 13:15
  • That has nothing to do with it. The standard mandates that they be, for all intents and purposes, left uninitialized in default construction unless you override that behaviour, just as if you had `int i;` in `main`. – chris Jun 24 '13 at 13:15
  • @user1873947 Maybe they are. Or maybe they aren't. Why would that matter, really? –  Jun 24 '13 at 13:15
  • @H2CO3 well my code depends that class members should be 0-initalized (and in many cases they are) – user1873947 Jun 24 '13 at 13:16
  • 1
    "I read that C standard says that pod should be always 0 initialized." You read wrong. (You may have misunderstood. There are some circumstances, e.g. `static` lifetime, where they are.) Also, this is `c++`. The `c` standard is not relevant (... mostly). – BoBTFish Jun 24 '13 at 13:16
  • @user1873947 I mean, does it count if they are on the stack? Uninitialized is uninitialized. The stack is not a magical "make me zero" place. And anyway, the C++ standard says/knows NOTHING about "the stack" as a concept. –  Jun 24 '13 at 13:18
  • Thank you all. I just understood the standard wrong. Now everything is clear. – user1873947 Jun 24 '13 at 13:31
  • @H2CO3 It does. The C++ standard has the concept of a function call stack. It doesn't have a name for it, but the rules are there. – R. Martinho Fernandes Jun 24 '13 at 13:31

3 Answers3

2

It depends:

Standardese

8.5. Initializers [dcl.init] / 11.

If no initializer is specified for an object, the object is default-initialized; if no initialization is performed, an object with automatic or dynamic storage duration has indeterminate value. [ Note: Objects with static or thread storage duration are zero-initialized, see 3.6.2. — end note ]

and (ordering reversed for readability):

8.5. Initializers [dcl.init] / 6.

To default-initialize an object of type T means:

— if T is a (possibly cv-qualified) class type (Clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);

— if T is an array type, each element is default-initialized;

otherwise, no initialization is performed. [emphasis mine]

If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.

They are default initialized. For builtin types like int or double, their value depends on where the struct is declared (as a rule of thumb (but just as that): Assume they are always garbage unless initialized).

In global scope or/and with static storage, they are all zeroes (incl. when the struct is a member of a struct which is at global scope).

At function-local scope, they are full of garbage.

Example:

#include <iostream>

struct Foo {
    int x;
    int y;
};

Foo foo;

int main () {
    Foo bar;

    std::cout << foo.x << ":" << foo.y << '\n';
    std::cout << bar.x << ":" << bar.y << '\n';
}

This on the first run gives me

0:0
-1077978680:12574708

On the second run, without recompilation, this gives me:

0:0
-1075556168:12574708

A POD-struct can be initialized all zeroes using e.g. memset or just ...

Foo foo = {0}; // C and C++03
Foo foo{0}; // C++11

Finally

You commented that your code depends on zero-initialization for those members. This is where you want a constructor:

class cMapRender
{
public:
    unsigned int m_rightMargin;
    unsigned int m_bottomMargin;
    unsigned int m_x;
    unsigned int test;
    unsigned int m_y;
    unsigned int m_width;
    unsigned int m_height;

    cMapRender() :
       m_rightMargin(0),
       m_bottomMargin(0),
       /* and so forth */
    {}
};

Apart from the design problems of your class (better group together some variables into a Rectangle-type), this would solve your issue.


(note: this answer was copied and modified from another answer by me (Initializing member variables of a struct in c++))

Community
  • 1
  • 1
Sebastian Mach
  • 38,570
  • 8
  • 95
  • 130
  • wouldn't it be better to set this question as duplicate instead of pasting? – Balog Pal Jun 24 '13 at 13:33
  • @BalogPal: My intention was to provide an answer to a question I did honestly not check otherwise. Often, different questions have the same answer. I don't see a duplicate-comment in the question. – Sebastian Mach Jun 25 '13 at 04:32
1

The language rules say your data members are uninitialized. You can value-initialize them like this:

cMapRender mapRender{}; // C++11

or

cMapRender mapRender1 = {};           // C++03 and C++11
cMapRender mapRender2 = cMapRender(); // C++03 and C++11

This will value initialize the data members, which means 0 initializing in this case.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
1

The C++ language is designed for "speed". By having the language standard define "unless you specifically write code for it, POD's are not initialize", the compiler doesn't have to generated code to set the POD's to some specific value. This in turn means that the code runs faster, because quite often, you'd then immediately set it to something else.

You can have a constructor, or you can use an initializer object to set it to zero, if you need that. Ideally, you'd have a constructor that takes the initial values, so the values aren't first set to zero, then to something else - since it doesn't look like most of your values would make sense to have as zero anyway.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227