6

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?

sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • I would recommend each member to be `const`. Especially when they are all `public` it really makes sense to force immutability. You can use array initialize syntax to create instances: `Struct s = { "...", 0 };` – Daniel Lidström Oct 14 '10 at 08:09
  • @Daniel: And when I want to put it in a container? – GManNickG Oct 14 '10 at 08:39
  • @GMan: I would place it in a `std::shared_ptr` in this case. Or maybe decide to properly encapsulate the members and remove the `const`. – Daniel Lidström Oct 14 '10 at 08:47
  • @Daniel: There's nothing wrong with all public members. – GManNickG Oct 14 '10 at 08:48
  • @GMan: I don't think it is a question of wrong or right. I have used the concept of immutability with public members of a struct as a kind of protection for myself. If you can enforce consistent state of a class with public modifiable member variables, then go ahead and do so. – Daniel Lidström Oct 14 '10 at 11:44
  • @Daniel: Okay, there's nothing wrong with mutable state. I'm not sure why you're pushing for immutable states, it seems out of the blue. – GManNickG Oct 14 '10 at 19:05
  • @GMan: It will force initialization. One way to solve the problem in question. – Daniel Lidström Oct 14 '10 at 20:23
  • @Daniel: I guess, not exactly a minor change though. I then reiterate that now it's noncopyable, and if I want it in a container it has to be dynamically allocated. Yuck. – GManNickG Oct 14 '10 at 20:25
  • @GMan: You don't necessarily have to agree here. Unless you are the one who posted the question, you don't know much about the situation where this will be applied. Please keep an open-minded attitude towards solutions you, at first sight, don't agree with. Curiousness is one of the trademarks of a good developer, in my opinion. – Daniel Lidström Oct 14 '10 at 20:33
  • 2
    @Daniel: I don't need you to play arm-chair psychiatrist with me, or call me closed-minded. Very rude. In this situation, given the information we have, making the members all `const` isn't a proper solution because you've *changed* what the class can do. There are other solutions that solve the problem that don't change the usability. While this doesn't eliminate the possibility your solution could be applied to different situations (which I never said), it does mean your solution falls a short relative to others. – GManNickG Oct 14 '10 at 20:47
  • If only there were a make it a compiler warning to not initialize a member variable in each initializer list – momeara Mar 23 '12 at 15:25

3 Answers3

10

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 ~ $ 
Community
  • 1
  • 1
Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
  • 1
    -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 Oct 14 '10 at 07:36
  • 7
    @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 Oct 14 '10 at 08:23
  • 4
    I learned something there -- my apologies. I'm removing the downvote and adding an upvote. – Martin B Oct 14 '10 at 09:06
10

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.

  • 1
    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 Oct 14 '10 at 07:43
  • 1
    @sharptooth: The idea is that you can use `initialized` almost like an `int`. For example, `initialized a; int b=a;` works. Without the conversion operators, you would need to access the `value` member explicitly. – Martin B Oct 14 '10 at 07:53
  • 1
    @Martin B: Yes, you're right about direct access, I didn't think of that. Still making `value` private makes no sense. – sharptooth Oct 14 '10 at 08:18
  • 1
    @sharptooth: value being private or not really important. It is just that when `initialized` is a fully interchangeable with `T`, you never need to access `value` anyway. –  Oct 14 '10 at 09:18
-1

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))
{
}
GManNickG
  • 494,350
  • 52
  • 494
  • 543
Jinyuan
  • 9
  • 1