How to zero-initialize an union? - c++

Consider the following code:
struct T {
int a;
union {
struct {
int a;
} s1;
struct {
char b[1024];
} s2;
};
};
int main() {
T x = T();
}
Since an explicit constructor is called, the above code ends-up zero-initializing all the data members in x.
But I would like to have x zero-initialized even if an explicit is not called. To do that one idea would be to initialize the data members in their declaration, which seems to be okay for T::a. But how can I zero-initialize all the memory occupied by the union by using
the same criteria?
struct T {
int a = 0;
union {
struct {
int a;
} s1;
struct {
char b[1024];
} s2;
};
};
int main() {
T x; // I want x to be zero-initialized
}

You could zeroize using memset:
memset(&x, 0, sizeof(x));

For a union without a user-defined default constructor, value initialization is zero initialization.
However, zero-initialization of a union may not zero all memory, but only the padding and the first member. If the first member isn't the largest, you could be left with non-zero content.
Since you know that s2 is largest, you can make a default constructor that zeros it:
struct T
{
int a;
union {
int s1a;
char s2b[1024];
};
T() : a(), s2b() {}
};
And now
T x;
will be zeroed.

I would suggest to implement a constructor for T:
struct T {
int a;
union {
struct {
int a;
} s1;
struct {
char b[1024];
} s2;
};
T() : a(), s2() {} // <- proper initialisation
};
In this case, I picked the largest member of your union since it's transparent. Otherwise you could explicitly create the union itself.

Related

Initialization behavior of class members of primitive type

I know there are quite a few answered questions here about this topic but I couldn't find one that fully answered my question.
Below I'm making some assumptions based on my understanding of initialization (as of C++17). It would be nice if someone could point out / correct my errors.
Given the type
struct A
{
int x;
};
creating a local variable doesn't initialize the object at all
A a; // a.x is indeterminate, accessing it is UB
However, we can enforce aggregate initialization by the following
A a{};
A a = {};
which initializes a.x to 0.
Now, given the type
struct B
{
int x;
std::string s;
};
creating a local variable default initializes the object
B b;
which results in b.s being default initialized (because it's a non-POD) but b.x being indeterminate, accessing it is still UB.
Next, we have
struct C
{
int x = 0;
std::string s;
};
creating a local variable default initializes the object
C c;
which results in C.s being default initialized (because it's a non-POD) and c.x being copy initialized, the behavior is well defined.
Finally, lets compare some types and check, whether they have identical initialization behavior. I'm assuming there is no difference between those types if I create a (default initialized) local variable (A a;).
Case A
struct A1
{
int x;
};
struct A2
{
A2() { }
int x;
};
struct A3
{
A3() = default;
int x;
};
x is never initialized, it's value is indeterminate.
Case B
struct B1
{
int x{};
};
struct B2
{
B2() : x{} { }
int x;
};
struct B3
{
B3() = default;
int x = 0;
};
x is always initialized, it's value is 0.
Case C
struct C1
{
int x;
std::string s;
};
struct C2
{
C2() { }
int x;
std::string s;
};
struct C3
{
C3() = default;
int x;
std::string s;
};
s is always default initialized, but x is never initialized, its value is indeterminate.
Are those statements correct and if not, where are the errors and what is the actual behavior?
You missed just one subtlety: for A3 or C3, writing T3 t{}; or T3() will initialize x to 0 because a default constructor defaulted on its first declaration causes value initialization to zero-initialize the object and default-initialize it.

extended initializer list and uninitialized members

In the old days structure like that:
typedef struct A {
int m_i;
int m_j;
} A;
Allocated on the heap or declared locally in a function without being memset would have its members uninitialized.
However, to my utter surprise this little program shows it is always set to 0.
#include <stdio.h>
typedef struct A {
int m_i;
int m_j;
} A;
void f(const A& a) {
printf("i=%i, j=%i\n", a.m_i, a.m_j);
}
void y() {
f({10});
}
int main() {
y();
return 0;
}
Built using g++ -std=c++11 a.cpp
I would just in case defined a constructor to make sure they are zero, but my various tests show (using code found on the internet) that I don't have to.
Is this a shear coincidence or extended initializer list is a guarantor of having memory being memset?
typedef struct A {
int m_i;
int m_j;
} A;
is an aggregate. When you initialize an aggregate with a braced-init-list it uses each element in the list to initialize each member of the aggregate. If you don't provide enough elements in the braced-init-list then each subsequent member is guaranteed to be value initialized, which for fundamental types means they are zero initialized..

C++ initialization list and constructor

C++14 provides the initialization list and we can use it to initialize elements in a class or struct. What are the differences of the two initialization manners in the following code?
struct MyItem {
MyItem() : val{0} {}
int val;
};
struct MyItem {
MyItem() {}
int val{0};
};
In your case, there is no difference. The first case uses a mem-initializer to initialize val. The second uses a brace-or-equal-initializer. A brace-or-equal-initializer will be used for a member when there is no mem-initializer present for that member. If there is a mem-initializer, it takes precedence, and the brace-or-equal-initializer is ignored.
One can certainly construct contrived examples where there is a difference...
const int i = 42;
struct S1 {
S1(int i): val{i} {} // sets val to the parameter i
int val;
};
struct S2 {
S2(int i) {} // param is ignored
int val{i}; // sets val to 42
};

const struct { x } vs struct { const x} [duplicate]

This question already has answers here:
How does a 'const struct' differ from a 'struct'?
(5 answers)
Closed 9 years ago.
This is a rather simple question, but somehow difficult to find a simple answer for.
In C++, what is the difference between an (edit) const-modified struct variable, and a(edit:) non-const struct variable, but with the struct having all-const members? :
typedef struct mystruct {
const int x;
} t1;
const t1 s1;
vs
typedef struct {
int x;
} t2;
const t2 s2;
? (If the answer is "the same as for classes", then please either explain it for classes or link to the explanation.)
There's no such thing as a const struct. You may have seen something like this:
const struct {
int x;
} y;
This is a declaration of a variable y with struct type. The variable y is const, not the struct. You can think of it as similar to:
struct mystruct {
int x;
};
const mystruct y;
without giving the struct type a name.
There's effectively very little difference between the two objects a and b below:
struct A
{
int x, y;
};
struct B
{
const int x, y;
};
const A a; // (plus initialiser)
B b; // (plus initialiser)
(You know, of course, that other instances of A may not be const-qualified and then you have an obvious difference.)
You can't access the members any differently in the one case than in the other. But:
You will have to ensure that you initialise the members, in both cases (which I haven't done here);
const-qualifiying the type (rather than the members) affects reference-binding:
void foo(A& a);
void foo(B& b);
int main()
{
const A a;
B b;
foo(a); // Error!
foo(b); // OK
}
The same is true, of course, if you use a pointer instead of a reference. The const context only spreads to calling code when it's applied to the type rather than encapsulated within the members.
Assuming
const struct mystruct1 {
int x1;
int x2;
} s1;
and
struct mystruct2 {
const int x1;
int x2;
} s2;
For s1 you should not assign values to any members.
For s2 only the member x1 should not be assigned a value. One is free to do so for x2.
To get closer to your example, one could do:
typedef const struct mystruct1 {
int x1;
int x2;
} S1;
typedef struct mystruct2 {
const int x1;
int x2;
} S2;
S1 s1;
S2 s2;
For s1 and s2 here the same rules apply as above.
Upate:
Referring your question literally (implying the corrections as by my examples), there is no practical difference between the two construct in terms constantness of the value they carry.

Is there a way to make a C++ struct value-initialize all POD member variables?

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?
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.
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 ~ $
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))
{
}