c++g++clang++compiler-optionsvalue-initialization

How to force compiler to set a non-zero value to uninitialized variables?


I am playing with C++ value initialization.
Therefore, I am printing uninitialized values in order to highlight (un)initialization depending on C++ standard version.
But uninitialized values convey often the zero value :-(

How to highlight if a variable has not been initialized?
(i.e., How to say to the compiler to use a specific value for uninitialized variables?)

Maybe this could be done using a magic user-provided allocator...


EDIT: My below snippets is not for production. I just wanted to check the implementation (by the compiler) of the C++ Standard about uninitialization/value-initialization/zero-initialization/default-initialization mechanisms. I do not want compiler warnings about uninitialized variables. I do not want to use MemoryCheckers. I just want to highlight that compiler zero-initializes some variables, default-initializes some other variables and does not initialize at all other variables. And this initialization behavior also depends on the version of C++ Standard. If you think the best way is to use compilers warnings or MemoryCheckers, please provide an answer using the below snippets.


Please do not read below detailed attempts if you have already understood my question.


You can build/run my first snippet on Coliru

#include <iostream>

struct A  {
  A() {} // user-defined default ctor does not initialize i
  int i;
};

struct B {
  A a;
};

int main()
{
  std::cout << B().a.i << '\n';
    // Results: C++03 -> uninitialized
    //          C++11 -> zero-initialized

  std::cout << B{}.a.i << '\n';
    // Results: C++03 -> Do not compile - B{} is correct since C++11
    //          C++11 -> uninitialized because
    //          DR1301 defines B{} as an aggregate-initialization
}   //          => A is value-initialized using the user-defined ctor

When compiled using -std=c++03 the execute may probably prints a zero value but I would prefer a non-zero value.

0

Possible output using -std=c++11

0
1208617840

Another possible output using -std=c++11

0
-201855824

But my more advanced snippet has now zero-values for uninitialized object B{}.a.i :-(

#include <iostream>

struct A {
  A() {} // user-defined ctor does not initialize i
  int i;
};

struct B  {
  A a;
};

int main()
{
  std::cout <<"-----------"<< __cplusplus <<"-----------" "\n";
  std::cout <<"B().a.i            = "<<         B().a.i <<'\n';
  std::cout <<"B{}.a.i            = "<<         B{}.a.i <<'\n';

  int d;
  d = 42;
  std::cout <<"(new(&d) B  )->a.i = "<< (new(&d) B  )->a.i <<'\n';
  d = 42;
  std::cout <<"(new(&d) B())->a.i = "<< (new(&d) B())->a.i <<'\n';
  d = 42;
  std::cout <<"(new(&d) B{})->a.i = "<< (new(&d) B{})->a.i <<'\n';
}

Build/Run output:

> g++ -std=c++03 -Wall -Wextra -pedantic main.cpp && ./a.out
-----------199711-----------
B().a.i            = 0
(new(&d) B  )->a.i = 42
(new(&d) B())->a.i = 0

> g++ -std=c++11 -Wall -Wextra -pedantic main.cpp && ./a.out
-----------201103-----------
B().a.i            = 0
B{}.a.i            = 0
(new(&d) B  )->a.i = 42
(new(&d) B())->a.i = 0
(new(&d) B{})->a.i = 0

> g++ -std=c++14 -Wall -Wextra -pedantic main.cpp && ./a.out
-----------201402-----------
B().a.i            = 0
B{}.a.i            = 0
(new(&d) B  )->a.i = 42
(new(&d) B())->a.i = 0
(new(&d) B{})->a.i = 0

Solution

  • One possible solution is to use clang++ instead of g++.

    clang++ v3.7 has highlighted uninitialized values in my specific case.

    Note: This answer is based on C++ value initialization that has changed since C++11. Value initialization is when parentheses/braces are empty: T(); T{}; new T(); new T{};

    Build/Run below snippet on Coliru

    #include <iostream>
    
    struct A
    {
      A() {} // ctor does not initialize 'i'
      int i;
    };
    
    struct B // implicit ctor
    {
      A a;
      int i;
      void set() { a.i = i = 42; }
    };
    
    std::ostream& operator<< (std::ostream& os, const B& b)
    {  os <<'\t'<< b.a.i <<'\t'<< b.i;  return os; }
    
    int main()
    {
      std::cout <<"----------"<< __cplusplus <<"----------" "\n";
    
      B b; // used to reset memory for 'placement new'
    
      b.set(); std::cout <<"new(&b)B   "<< *new(&b)B   <<'\n'; // All uninitialized (in all C++ standards)
    
      std::cout          <<"       B() "<< B()         <<'\n'; // B::A::i uninitialized in C++03, zero-initialized in C++11
      b.set(); std::cout <<"new(&b)B() "<< *new(&b)B() <<'\n'; // B::i zero-initialized (in all C++ standards)
    
    #if __cplusplus > 2011*100                                 // B{} is aggregate-initialization (DR1301)
      std::cout          <<"       B{} "<< B{}         <<'\n'; // => B::A::i value-initialized
      b.set(); std::cout <<"new(&b)B{} "<< *new(&b)B{} <<'\n'; // => B::i     zero-initialized
    #endif
    }
    

    Build output & Possible run output

    > clang++ --version
    clang version 3.7.0 (tags/RELEASE_370/final 246979)
    Target: x86_64-unknown-linux-gnu
    Thread model: posix
    
    > clang++ -std=c++03 -Wall -Wextra -pedantic main.cpp && ./a.out
    ----------199711----------
    new(&b)B    42      42
           B()  0       0
    new(&b)B()  0       0
    
    > clang++ -std=c++11 -Wall -Wextra -pedantic main.cpp && ./a.out
    ----------201103----------
    new(&b)B    42      42
           B()  0       0
    new(&b)B()  0       0
           B{}  4196348 0
    new(&b)B{}  42      0
    
    > clang++ -std=c++14 -Wall -Wextra -pedantic main.cpp && ./a.out
    ----------201402----------
    new(&b)B    42      42
           B()  0       0
    new(&b)B()  0       0
           B{}  4196348 0
    new(&b)B{}  42      0
    
    > clang++ -std=c++1z -Wall -Wextra -pedantic main.cpp && ./a.out    
    ----------201406----------
    new(&b)B    42      42
           B()  0       0
    new(&b)B()  0       0
           B{}  4196348 0
    new(&b)B{}  42      0