views:

183

answers:

3

Suppose I have a C++ struct that has both POD and non-POD member variables:

struct Struct {
    std::string String;
    int Int;
};

and in order for my program to produce reproduceable behavior I want to have all member variables initialized at construction. I can use an initializer list for that:

 Struct::Struct() : Int() {}

the problem is as soon as I need to change my struct and add a new POD member variable(say bool Bool) I risk forgetting to add it to the initializer list. Then the new member variable will not be value-initialized during struct construction.

Also I can't use the memset() trick:

Struct::Struct()
{
   memset( this, 0, sizeof( *this ) ); //can break non-POD member variables
}

because calling memset() to overwrite already constructed non-POD member variables can break those.

Is there a way to enforce value-initialization of all POD member variables without explicitly adding their initialization in this case?

+13  A: 

Linked Question here

Is there a way to enforce value-initialization of all POD member variables without explicitly adding their initialization in this case?

I am not sure whether something like that is possible [directly] or not but the following works

prasoon@prasoon-desktop ~ $ cat check.cpp && clang++ check.cpp && ./a.out
#include <iostream>
struct Struct {
    std::string String;
    int Int;
    bool k;
    // add add add
};

struct InStruct:Struct
{
   InStruct():Struct(){}
};

int main()
{
   InStruct i;
   std::cout<< i.k << "  " << i.Int << std::endl; 
}
0  0
prasoon@prasoon-desktop ~ $ 
Prasoon Saurav
-1 You're just lucky and are getting zeros because the memory that `i` was placed in happened to be zero-initialized. This is _not_ guaranteed by the standard.
Martin B
@Martin B : I think it is guaranteed by C++03. Please have a look at my question [here](http://stackoverflow.com/questions/3931312/value-initialization-and-non-pod-types)
Prasoon Saurav
I learned something there -- my apologies. I'm removing the downvote and adding an upvote.
Martin B
+4  A: 

The cleanest way would be to write the auto-initialzed template class initialized<T>:

EDIT: I realize now it can be made even more flexible by allowing you to declare initialized<Struct>. This means that you can declare initialization without modifying the original Struct. The default initialization 'T()' was inspired on Prasoons answer.

template<class T>  
struct initialized 
{ 
public: 

     initialized() 
        { value = T(); }

    initialized(T t) 
        { value = t; }

    initialized(const initialized<T>& x) 
        { value = x.value; }

    T* operator &() { return &value; } 

     operator T&() { return value; }     

private: 
     T value; 
};


struct PodStruct 
{            
    std::string String;      
    int Int; 
};  


struct GlorifiedPodStruct 
{            
    std::string String;      
    initialized<int> Int; 
};  

void Test()
{
    GlorifiedPodStruct s;
    s.Int = 1;
    int b = s.Int;
    int * pointer = &s.Int;

    initialized<PodStruct> s2;
}

This compiles, but may need more conversion operators, handling of keywords like volatile, etc. But you get the idea.

jdv
Hmmm. Looks good, but what't the purpose of making `value` private and then providing full access to it anyway? Wouldn't it be cleaner to just make it public and remove the conversions?
sharptooth
@sharptooth: The idea is that you can use `initialized<int>` almost like an `int`. For example, `initialized<int> a; int b=a;` works. Without the conversion operators, you would need to access the `value` member explicitly.
Martin B
@Martin B: Yes, you're right about direct access, I didn't think of that. Still making `value` private makes no sense.
sharptooth
@sharptooth: value being private or not really important. It is just that when `initialized<T>` is a fully interchangeable with `T`, you never need to access `value` anyway.
jdv
@Martin B: Thanks for clarifying.
jdv
A: 

You can add a base struct:

struct PODStruct
{
  PODStruct(unsinged int count) { memset( this, 0, count);}
};

And then your struct derived from this base struct, first place if you have more than one base structs,

struct Struct : PODStruct
{
  Struct();
  std::string Str;
  int Int;
}

Struc::Struct() : PODStruct(sizeof(Struct))
{
}
Jinyuan
This leads to UB. You can't `memset` over a non-POD type, like `std::string`.
GMan