2

I have read on Stack Overflow that global/static variables are initialized to their default value (0).

I also read somewhere else (not sure tho), that class variables (non-static) are also initialized to 0. Is this true?

Specifically, I am wondering whether my pointers are by default initialized to nullptr.

I tried compiling on g++ and clang and both seem to initialize them to nullptr.

#include <iostream>

struct Foo {
    int *ptr;
};

int main() {
    Foo f;
    std::cout << f.ptr;
}

printed:

0

If it's only my compiler doing it, is there any way I can tell my compiler not to do this (using some compiler flag)?

Priyanshul Govil
  • 518
  • 5
  • 20
  • 3
    there is absolutely no difference between struct members and class members: https://stackoverflow.com/a/36917400/4117728 – 463035818_is_not_an_ai Feb 16 '21 at 16:18
  • 2
    You can't determine by looking at something whether it has been initialized or not (on the current mainstream architectures). – molbdnilo Feb 16 '21 at 16:20
  • 1
    you cannot reliably check whether something is not initialized. In the code you used to convince yourself that they are initialized to `nullptr` they may well be not initialized and all you see is UB in action. Better include your code here – 463035818_is_not_an_ai Feb 16 '21 at 16:20
  • 1
    There's no difference between pointer members and non-pointer members: They are both members and are treated the exact same way when it comes to initialization. – Some programmer dude Feb 16 '21 at 16:20
  • 1
    this story about "garbage" is a misleading myth. If you print the value of an uninitialized pointer then `0` is just as "garbage" as any other value. – 463035818_is_not_an_ai Feb 16 '21 at 16:22
  • 1
    Your OS may initialize a page to 0 the first time it gives a page to your process to prevent information leaking from other processes (security measure). This may fool you to believing the memory is initialized to 0 every time when it is not. Also when you free memory in your c++ program it may not be given back to the OS and instead reused for future allocations of your same process so the next time it will not have this OS initialization. – drescherjm Feb 16 '21 at 16:24
  • 2
    *"both seem to initialize them to nullptr"* debug builds tend to initialize some memory to 0 (even if variable is still not initialized)... – Jarod42 Feb 16 '21 at 16:24
  • 1
    Perhaps you read something about "zero-initialisation" (https://en.cppreference.com/w/cpp/language/zero_initialization) which is not equal to "default-initialisation". Could you post the code where both compilers initialized a non static member of a pointer-type to zero? – Bernd Feb 16 '21 at 16:47
  • @Bernd yeah, I'll just update the question. – Priyanshul Govil Feb 16 '21 at 16:52
  • 1
    Here you have default-initialization. This means a compiler is allowed to initialize your struct with null-bytes but is not required to do so. You should test such things with O2 or O3. UB is often just visible with optimization... – Bernd Feb 16 '21 at 17:04
  • @Bernd Could you please provide a reliable source from where I can understand about default-initialization. Also, is there any compile flag I can use to tell my compiler not to perform default-initialization? – Priyanshul Govil Feb 16 '21 at 17:05
  • 1
    Of course. The most reliable source is the C++ standard - which can be found as a draft here: https://github.com/cplusplus/draft. This is usually the source used by compiler writers. But for usual programmers you can just look at https://en.cppreference.com which is a basically a simplified version of the C++ standard. E.g.: https://en.cppreference.com/w/cpp/language/default_initialization – Bernd Feb 16 '21 at 17:09

2 Answers2

5

I also read somewhere else (not sure tho), that class variables (non-static) are also initialized to 0.

Wherever you read that (if you read that), then stop reading that source!

Is this true?

No.

Here's a short example:

#include <iostream>

class Foo {
public:
    int* ip; // Do we get default initialization to "nullptr" ?? ...
    Foo() = default;
};

int main()
{
    Foo Bar;
    std::cout << Bar.ip << std::endl; // ... print the "ip" pointer to see!
    return 0;
}

The output when building with clang-cl and running on Windows 10 is (but the actual value varies):

00000272B7D941D0

When compiling with MSVC, the following message is given:

warning C4700: uninitialized local variable 'Bar' used

Of course, some compilers may set such uninitialized memory to zero, and even when built with Clang or MSVC, as above, the initial value of the pointer may occasionally just happen to be zero. However, the warning from MSVC should be taken seriously. Furthermore, the static analyser that clang-cl uses gives a more specific warning:

std::cout << Bar.ip << std::endl;
^
warning GDEC5F24A: 1st function call argument is an uninitialized value [clang-analyzer-core.CallAndMessage]

is there any way I can tell my compiler not to do this (using some compiler flag)?

Probably not – but you can enable all compiler warnings, which will show you cases where you have such behaviour.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • 2
    imho it is important to note that the code could produce the same output as if the pointer was initialized to `nullptr` but nevertheless exhibits UB. It is possible to demonstrate the presence of UB via some output but never the absence of UB – 463035818_is_not_an_ai Feb 16 '21 at 16:25
  • 1
    @largest_prime_is_463035818: `constexpr` evaluation should not contains UB, so there is a way (even if limited as not all code can go in constexpr). – Jarod42 Feb 16 '21 at 16:28
  • 1
    uh right. I love it when my nitpick gets nitpicked :). My point was just that OP tried to check their assumption and concluded that pointers are initialized because they got output that is in accordance with pointers getting initialized to `nullptr`. But thats based on a false premise and expecting "garbage" to look like garbage – 463035818_is_not_an_ai Feb 16 '21 at 16:31
  • 2
    @largest_prime_is_463035818 I'm looking now through the C++ Standard for the bit that says what we know it *should* say. I'll add that excerpt if/when I find it... – Adrian Mole Feb 16 '21 at 16:37
  • 1
    There is an exception. When a struct or class is partially initialized, any fields not explicitly given a value are set to 0. E.g. given `struct {int *a; int *b} s = {nullptr};`, b will also be null. – John Bayko Feb 16 '21 at 18:46
  • 1
    @JohnBayko That only works for classes/structures that are *aggregate types* (i.e. have no user-defined constructors, no private/protected members, no base classes and no virtual functions). ... I think. – Adrian Mole Feb 16 '21 at 18:51
3

Pointers are not initialized when they are instantiated. Unless a value is assigned, a pointer will point to some indeterminate value (garbage address) by default. Some compilers will assign nullptr for pointers but that's not standard so don't count on it. Always initialize raw pointers and check against null before using them.

Moreover, structs and classes are interchangeable. Of course, a struct default visibility for its members is public while class attributes are private.

Oussama Ben Ghorbel
  • 2,132
  • 4
  • 17
  • 34
  • 2
    Instead of `garbage address` you should say indeterminate value. Depending on the order of execution a struct could be created at the same memory location like a previous destructed one. (Not uncommon for variables with automatic storage duration) and then the pointer might contain a value that seems to be valid, but is still an indeterminate value and reading such a value would result in undefined behavior. – t.niese Feb 16 '21 at 16:30
  • 1
    @t.niese I totally agree "indeterminate value" is the better term to use here. – Oussama Ben Ghorbel Feb 16 '21 at 16:32