ZAB
ZAB

Reputation: 1015

Forcing local variables to be default-initialized

In C++, plain-old-data (POD) local variables are uninitialized by default. I've noticed, though, that this leads to bugs, since attempting to read the value of an uninitialized variable is undefined behavior.

Is there a way to force the compiler to automatically initialize all local variables? Perhaps a compiler that has this feature built in, or a compiler switch for one of the common compilers, like GCC or Clang? I would be fine with a Gnu extension; it doesn't have to be standard.

I would expect the variables to be default-initialized, meaning that an int would be set to 0.

I am bored with assigning all local ints and private class fields to 0.

Upvotes: 2

Views: 3663

Answers (2)

ZAB
ZAB

Reputation: 1015

There is a proposal to compile linux kernel with zero initialized local variables, see the presentation from linux.conf this year https://youtu.be/FY9SbqTO5GQ?t=742

To accomplish this the presenter team used an experimental gcc switch finit-local-vars, patch is here https://gcc.gnu.org/ml/gcc-patches/2014-06/msg00615.html

I hope this will be eventually merged to gcc main branch and adopted widely. Literally every code style guide I've seen demanded C/C++ coders to make an explicit zero assignment = 0 wherever they defined a variable. This is error prone and meaningless monkey work.

EDIT 2022: A switch -ftrivial-auto-var-init was added to GCC 12

Upvotes: 0

Jean-François Fabre
Jean-François Fabre

Reputation: 140168

There is no switch to do that I know about, and even if it did exist, it would be only a "debug" feature, not to be used in production code.

Example: Electric fence library has an option to initialize memory to 0 or 0xff

EF_FILL When set to a value between 0 and 255, every byte of allocated memory is initialized to that value. This can help detect reads of uninitialized memory. When set to -1, some memory is filled with zeroes (the operating system default on most systems) and some memory will retain the values written to it during its last use.

(only works for allocated memory, not automatic memory).

Relying on a switch that isn't defined as/in a standard would make your code non-portable. At some point, someone will use your code to cross compile it on other platforms and that will fail.

As a help/safeguard, some tools like Coverity (note: I'm not affiliated with this company) can detect uninitialized POD members in your code. There may be free tools that do the same.

So what I would do in cases of one or 2 POD members (c++11):

class Foo
{
   ...
   private:
      int x = 0;
      int y = 0;
};

If you have a zillion members, maybe create a POD class/struct, create 1 member with this type and initialize it to 0 using whatever initialization works best:

class Foo
{
   ...
   private:
      struct Pod
      {
        int x,y,z,whatever;
      };
      Pod m = {0};
};

That forces to access members like m.x, ... not transparent

OR (maybe slightly hacky but works), create a POD structure, then inherit your class from it. You can now apply memset on the size of the POD structure in the default constructor

  struct Pod
  {
    Pod()
    {
       std::memset(this,0,sizeof(Pod));
    }
    int x,y,z,whatever;
  };

  class Foo : private Pod
  {
     public:
       ...
      private:
        std::string name;
        std::vector<int> elements;
  };

The sizeof(Pod) value ensures that memset only sets the members of Pod to 0.

If Pod comes from a C structure that you cannot change, you can move the memset statement in Foo constructor, keeping sizeof(Pod)

Upvotes: 1

Related Questions