107

Our code involves a POD (Plain Old Datastructure) struct (it is a basic c++ struct that has other structs and POD variables in it that needs to get initialized in the beginning.)

Based one what I've read, it seems that:

myStruct = (MyStruct*)calloc(1, sizeof(MyStruct));

should initialize all the values to zero, as does:

myStruct = new MyStruct();

However, when the struct is initialized in the second way, Valgrind later complains "conditional jump or move depends on uninitialised value(s)" when those variables are used. Is my understanding flawed here, or is Valgrind throwing false positives?

Community
  • 1
  • 1
KC3BZU
  • 1,224
  • 2
  • 11
  • 14
  • Releated FAQ: http://stackoverflow.com/questions/620137/do-the-parentheses-after-the-type-name-make-a-difference-with-new/620402#620402 – Robᵩ May 06 '11 at 16:59
  • As I understand things, you should not get that error message. Perhaps your data structure is not a POD? Can you reduce your code to the smallest program that still demonstrates this behavior, and post that distilled program? (See http://sscce.org). – Robᵩ May 06 '11 at 17:03
  • 1
    What compiler? Can you post the definition of MyStruct? – Alan Stokes May 06 '11 at 17:04
  • ah i see now how you meant it originally. – Johannes Schaub - litb May 06 '11 at 17:06
  • [This program](http://ideone.com/rBOyJ) fits your description, but on Ubuntu LTS 10.04.2, does not produce the errors you describe. – Robᵩ May 06 '11 at 17:09

7 Answers7

151

In C++ classes/structs are identical (in terms of initialization).

A non POD struct may as well have a constructor so it can initialize members.
If your struct is a POD then you can use an initializer.

struct C
{
    int x; 
    int y;
};

C  c = {0}; // Zero initialize POD

Alternatively you can use the default constructor.

C  c = C();      // Zero initialize using default constructor
C  c{};          // Latest versions accept this syntax.
C* c = new C();  // Zero initialize a dynamically allocated object.

// Note the difference between the above and the initialize version of the constructor.
// Note: All above comments apply to POD structures.
C  c;            // members are random
C* c = new C;    // members are random (more officially undefined).

I believe valgrind is complaining because that is how C++ used to work. (I am not exactly sure when C++ was upgraded with the zero initialization default construction). Your best bet is to add a constructor that initializes the object (structs are allowed constructors).

As a side note:
A lot of beginners try to value init:

C c(); // Unfortunately this is not a variable declaration.
C c{}; // This syntax was added to overcome this confusion.

// The correct way to do this is:
C c = C();

A quick search for the "Most Vexing Parse" will provide a better explanation than I can.

Martin York
  • 257,169
  • 86
  • 333
  • 562
  • 1
    Do you have a reference for this zero-initialising of variables in C++? Last I heard, it still has the same behaviour as C. IIRC, the MSVC compiler even dropped zero-initialising uninitialised members at some point (for performance reasons, I assume), which apparently created rather severe problems for the other MS divisions :) – Marc Mutz - mmutz May 06 '11 at 17:10
  • @mmutz: You mean the `C c = {0};` – Martin York May 06 '11 at 17:12
  • 1
    no, the `C()`, but it seems [you are right](http://stackoverflow.com/questions/620137/do-the-parentheses-after-the-type-name-make-a-difference-with-new/620402#620402). – Marc Mutz - mmutz May 06 '11 at 17:17
  • 4
    With a POD class, `T`, `T()` has always zero initialized the scalar subobjects. The name of the toplevel initialization was called different in C++98 than in C++03 ("default initialization" vs "value initialization"), but the end effect for PODs are the same. Both C++98 and C++03 would have all values in it be zero. – Johannes Schaub - litb May 06 '11 at 17:25
  • How to call default ctor in this manner for `struct sigaction` from `#include ` POSIX? this struct has the same name as function sigaction – yanpas Aug 16 '16 at 16:29
  • @yanpas As this is a C class it has no constructor. It can either be value initialized or zero-initialized. You can also use the original C syntax for initializing a structure. `struct sigaction actionObject = {func, other1, other2};` – Martin York Aug 16 '16 at 17:16
  • If it is C class and has no ctor will calling it's default constructor zero initialize it? – yanpas Aug 16 '16 at 17:21
  • @yanpas It has no constructor to call. So you can not call the default constructor. **BUT** zero initialization is a specific initialization mode of objects described by the standard. It happens under very specific situations (as described above). Though I will give you that it looks exactly like a default constructor call. – Martin York Aug 16 '16 at 17:25
  • Can you show the recommended syntax to pass a zero-initialized POD as a function argument? Unsure, but maybe... `(C){0}`, but the "cast to type C" looks weird. – kevinarpe Mar 12 '17 at 15:36
  • If the struct has more than one element, `C c = { 0 }` triggers a warning with `-Wextra`, unlike `C c = {}`. The latter is also specified in the standard: http://en.cppreference.com/w/cpp/language/zero_initialization. – krlmlr Jul 24 '17 at 23:42
  • @yanpas I think the relevant section of the standard is [dcl.init.list] (list item 3.4) – MattR Oct 26 '17 at 18:36
  • @MartinYork, I am confused by your last code snippet and attached statements. Isn't `C c();` actually a _direct initialization_ on the stack using the default constructor with no parameters? Whereas `C c = C()` is called _copy-initialization_? Please check [this question](https://stackoverflow.com/questions/1758142/why-copy-constructor-is-not-called-in-this-case) which explains the two types of initializations. Can you please explain "Unfortunately this is not a variable declaration." in a comment or by modifying your answer? – octo Aug 15 '18 at 07:36
  • 2
    @RockyRaccoon `C c();` unfortunately is not a variable declaration but rather a forward declaration of a function (A function called 'c' that takes no parameters and returns an object of type C). Google: Most Vexing Parse – Martin York Aug 15 '18 at 17:15
  • @RockyRaccoon The declaration `C c = C()` is not actually a copy-initialization (though it does look like one (and I also originally (and incorrectly) though of it that way; I thought he compiler was just smart enough to optimize out the copy so you never saw the copy). BUT this is explicitly called out in the standard as a construction only. – Martin York Aug 15 '18 at 17:18
  • 1
    @RockyRaccoon The difference here and with the question you link to in your comment; is that in this case there are no parameters used in the construtor. So the compiler has a hard time parsing this and telling the difference between variable declaration and forward declaration of a function. It chooses forward function declaration. If you require a parameter in the constructor then the compiler can see this is a variable declaration without any issues. `C c(4);` Is a valid variable declaration. – Martin York Aug 15 '18 at 17:21
  • @MartinYork, thanks for the replies. I understand the issue now. I also read the 'Most vexing parse' wiki. In light of these - do you think that _copy-initialization_ should always be used when initializing local objects, since it is not prone to these errors (traps)? I also understand that copy-initialization does not do extra operations of calling the extra copy constructor - since it is optimized by the compiler most of the times, unless you disable _copy-elision_ (G++ `-fno-elide-constructors` flag). – octo Aug 15 '18 at 17:40
  • @RockyRaccoon This is why `{}` initialization was added to the language. `C c{};` is unambiguous and does what you expect. – Martin York Aug 15 '18 at 20:16
  • @MartinYork, this is still not unambiguous as you need to aware of classes which implement an initializer_list constructor - then it is prioritised over the other constructors and does not behave as using the older syntax: `std::vector v1(3, 0);` and `std::vector v2 = std::vector(3, 0);` result in vectors with three 0 elements each while `std::vector v3{ 3, 0 };` and `std::vector v4 = std::vector{ 3, 0 };` will initialize vectors with two elements, 3 and 0. So is there another method which is really _sound_? – octo Aug 16 '18 at 05:58
  • @RockyRaccoon You are confusing your constructors. This question is only about default construction. Sure your class may overide the constructor with `std:: initializer_list` but an empty initializer list and a default constructor (you would hope) do logically the same thing. But that is why we also have code review. – Martin York Aug 17 '18 at 15:44
3

I write some test code:

#include <string>
#include <iostream>
#include <stdio.h>

using namespace std;

struct sc {
    int x;
    string y;
    int* z;
};

int main(int argc, char** argv)
{
   int* r = new int[128];
   for(int i = 0; i < 128; i++ ) {
        r[i] = i+32;
   }
   cout << r[100] << endl;
   delete r;

   sc* a = new sc;
   sc* aa = new sc[2];
   sc* b = new sc();
   sc* ba = new sc[2]();

   cout << "az:" << a->z << endl;
   cout << "bz:" << b->z << endl;
   cout << "a:" << a->x << " y" << a->y << "end" << endl;
   cout << "b:" << b->x << " y" << b->y <<  "end" <<endl;
   cout << "aa:" << aa->x << " y" << aa->y <<  "end" <<endl;
   cout << "ba:" << ba->x << " y" << ba->y <<  "end" <<endl;
}

g++ compile and run:

./a.out 
132
az:0x2b0000002a
bz:0
a:854191480 yend
b:0 yend
aa:854190968 yend
ba:0 yend
Yadong
  • 31
  • 2
  • Ok, I'm not so familiar with `new sc;` vs `new sc();` . I would have thought the missing parens was an error. But this seems to demonstrate that the answer is correct (it does init to 0 when you use the default constructor.) – nycynik Apr 10 '19 at 05:45
  • A good example! – John Sep 14 '22 at 03:50
2

From what you've told us it does appear to be a false positive in valgrind. The new syntax with () should value-initialize the object, assuming it is POD.

Is it possible that some subpart of your struct isn't actually POD and that's preventing the expected initialization? Are you able to simplify your code into a postable example that still flags the valgrind error?

Alternately perhaps your compiler doesn't actually value-initialize POD structures.

In any case probably the simplest solution is to write constructor(s) as needed for the struct/subparts.

Mark B
  • 95,107
  • 10
  • 109
  • 188
0

Since it's a POD struct, you could always memset it to 0 - this might be the easiest way to get the fields initialized (assuming that is appropriate).

Scott C Wilson
  • 19,102
  • 10
  • 61
  • 83
  • 1
    Whether it's a struct or a class has nothing to do with the ability to memset or create a constructor. See e.g. http://stackoverflow.com/questions/2750270/c-c-struct-vs-class – Erik May 06 '11 at 16:43
  • You wouldn't normally memset a class after creating it, since its constructor (presumably) did the initialization. – Scott C Wilson May 06 '11 at 16:44
  • 2
    there's no difference between "class" and "struct" in C++, except for the default protection (private and public, resp.). A struct can be a non-POD and a class can be a POD, these concepts are orthogonal. – Marc Mutz - mmutz May 06 '11 at 16:47
  • @mmutz and @Erik - agreed - shortened my answer to prevent confusion. – Scott C Wilson May 06 '11 at 17:19
  • memset() is not the best option, you can zero-initialize a POD struct by just calling its default ctor. – Nils Aug 20 '12 at 07:39
0

That seems to me the easiest way. Structure members can be initialized using curly braces ‘{}’. For example, following is a valid initialization.

struct Point 
{ 
   int x, y; 
};  

int main() 
{ 
   // A valid initialization. member x gets value 0 and y 
   // gets value 1.  The order of declaration is followed. 
   struct Point p1 = {0, 1};  
}

There is good information about structs in c++ - https://www.geeksforgeeks.org/structures-in-cpp/

Michael Klishevich
  • 1,774
  • 1
  • 17
  • 17
0
    You can declare and initalise structure in C++ this way also:::
    
    struct person{
        int a,h;
     
        person(int a1,int h1): a(a1),h(h1){
            
        }// overriden methods

        person():a(0),h(0){
            
        }// by default
    };

   struct person p; 
   --> This creates from by default Person Age: 0 height: 0

   struct person p = person(3,33);  
    --> This creates from overriden methods Person Age: 3 height: 33
     

     
-1

You need to initialize whatever members you have in your struct, e.g.:

struct MyStruct {
  private:
    int someInt_;
    float someFloat_;

  public:
    MyStruct(): someInt_(0), someFloat_(1.0) {} // Initializer list will set appropriate values

};
rtn
  • 127,556
  • 20
  • 111
  • 121