I have many POD struct with a lot of member variables. Instead of initializing each members in the constructor, I simply use memset. Is this valid in C++?
struct foo
{
foo() { std::memset(this, 0, sizeof (foo)); }
int var1;
float var2;
double var3;
// more variables..
};
It's not guaranteed to work, since the C++ standard permits implementations in which all-bits-zero is a trap representation of float or double. So reading those members on such an implementation would have undefined behavior.
The same applies to any padding bytes that the implementation might put between the data members -- modifying them is either undefined behavior or else puts the object into an undefined state, that has undefined behavior when used. I forget which.
In practice it will work on all implementations I know, though.
Other answers make valid points about your class being non-POD (C++03) and non-trivial (C++11). Thing is, even if you removed the constructor and called memset from somewhere else it would still not be guaranteed to work by the standard. But if you did remove the constructor you could use aggregate initialization:
foo f = {0};
and that would intialize all members to zero values (whether or not that is represented by all-bits-zero), guaranteed.
According to standard your struct is not POD type and thus it is not allowed to use memset.
9 Classes
A trivial class is a class that has a default constructor (12.1), has no non-trivial default constructors ,
and is trivially copyable
10 A POD struct108 is a non-union class that is both a trivial class and a standard-layout class, and has no
non-static data members of type non-POD struct, non-POD union (or array of such types).
Since your class have non-trivial default constructor it is no longer trivial, and as result not a POD type.
Most likely is will be working on most of the compilers, no guarantee thru.
Related
In C++11, I have the following union:
union SomeData
{
std::uint8_t Byte;
std::uint16_t Word;
std::uint32_t DWord;
unsigned char String[128];
};
If I initialize the union thusly;
SomeData data {};
Is it guaranteed that the entire contents of the union will be "zero'd" out? Put another way; is an empty list-initializer of a union functionally equivalent to memset-ing the union to Zero?:
memset(&data, 0, sizeof(data));
In particular, I'm concerned about the string data. I'd like to ensure the entire length of the string contains zeros. It appears to work in my current compiler, but does the language of the spec guarantee this to always be true?
If not: is there a better way to initialize the full length of the union to zero?
No, it is not guaranteed that the entire union will be zeroed out. Only the first declared member of the union, plus any padding, is guaranteed to be zeroed (proof below).
So to ensure the entire memory region of the union object is zeroed, you have these options:
Order the members such that the largest member is first and thus the one zeroed out.
Use std::memset or equivalent functionality. To prevent accidentally forgetting that, you can of course give SomeData a default constructor which will call this.
Quoting C++11:
8.5.4 [dcl.init.list]/3
List-initialization of an object or reference of type T is defined as follows:
If the initializer list has no elements and T is a class type with a default constructor, the object is
value-initialized.
8.5 [dcl.init]/7
To value-initialize an object of type T means:
if T is a (possibly cv-qualified) class type (Clause 9) with a user-provided constructor (12.1), then the
default constructor for T is called (and the initialization is ill-formed if T has no accessible default
constructor);
if T is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object
is zero-initialized and, if T’s implicitly-declared default constructor is non-trivial, that constructor is
called.
...
otherwise, the object is zero-initialized.
8.5 [dcl.init]/5:
To zero-initialize an object or reference of type T means:
...
if T is a (possibly cv-qualified) union type, the object’s first non-static named data member is zero-initialized
and padding is initialized to zero bits;
From these quotes, you can see that using {} to initialise data will cause the object to be value-initialized (since SomeData is a class type with a default constructor).
Value-initializing a union without a user-provided default constructor (which SomeData is) means zero-initializing it.
Finally, zero-initializing a union means zero-initializing its first non-static named data member.
The entire union will be zeroed out. More exactly the first member of the union will be default initialized and all the remaining bytes in the union will be set to 0 as padding.
References (emphasize mine):
8.5 Initializers [dcl.init]...
5 To zero-initialize an object or reference of type T means:...
— if T is a (possibly cv-qualified) union type, the object’s first non-static named data member is zero initialized
and padding is initialized to zero bits;
That means that the first member of the union (here std::uint8_t Byte;) will be initialized to a 0 and that all other bytes in the union will be set to 0 because they are padding bytes.
But beware. As stated by Angew "padding" is wonderfully underspecified in the standard and a C compiler could interpret that the padding bytes in a union are only the bytes that follow the largest member. I would really find that weird because compatibility changes are specifically documented and previous versions (C) first initialized everything to 0 and next did specific initialization. But a new implementer could not be aware of it...
TL/DR: I really think that the intent of the standard is that all bytes in the union are set to 0 in OP's example, but for a mission critical program, I would certainly add an explicit 0 constructor...
Let's say I have a class with a member array of std::atomics, where the
array is sized via a computation (i.e. it may change based on other constants elsewhere in the program):
class Foo {
static constexpr size_t kArraySize = ComputeArraySize();
std::atomic<size_t> atomics_[kArraySize];
};
What is the most elegant way to ensure that the atomics are all initialized to
zero? Can I do better than looping over the array in Foo's constructor and
explicitly storing zero? Does the answer differ for std::array?
Normally I would use a brace initializer here, but the derived length (which
may be long) makes it difficult.
Note that I cannot assume that the instance of Foo has static storage
duration.
Okay, I believe I've worked this through. Both of these will initialize all of
the atomics to zero:
std::atomic<size_t> plain_array[kArraySize] = {};
std::array<std::atomic<size_t>, kArraySize> std_array = {};
Here's the logic:
[dcl.init.aggr]/1 defines arrays to be aggregates.
[array.cons]/1 mandates that std::array also be an aggregate.
[dcl.init.aggr]/7 says that if there are fewer elements of the initializer
list than there are members in the aggregate, then the remaining members
shall be initialized from an empty initializer list. In this case, that's
all members.
[dcl.init.list]/3 defines list-initialization from an empty list for a class
with a default constructor (as with std::atomic) to cause
value-initialization.
[dcl.init]/7 says that classes without user-provided constructors are
zero-initialized. Assuming that std::array<T> contains an array of T,
and that the zero representation of std::atomic<size_t> is what we expect,
then we're good.
Now, std::atomic does have a user-provided constructor, just not a
user-provided default constructor (the latter is explicitly defaulted). So
it doesn't technically fit the conditions of the last point. But it seems this
is an error in the standard, and has been fixed in more recent
drafts.
I was trying to learn more about unions and their usefulness, when I was surprised that the following code is perfectly valid and works exactly as expected:
template <class T>
union Foo
{
T a;
float b;
Foo(const T& value)
: a(value)
{
}
Foo(float f)
: b(f)
{
}
void bar()
{
}
~Foo()
{
}
};
int main(int argc, char* argv[])
{
Foo<int> foo1(12.0f);
Foo<int> foo2((int) 12);
foo1.bar();
foo2.bar();
int s = sizeof(foo1); // s = 4, correct
return 0;
}
Until now, I had no idea that it is legal to declare unions with templates, constructors, destructor, and even member functions. In case it's relevant, I'm using Visual Studio 2012.
When I searched the internet to find more about using unions in this manner, I found nothing. Is this a new feature of C++, or something specific to MSVC? If not, I'd like to learn more about unions, specifically examples of them used like classes (above). If someone could point me to a more detailed explanation of unions and their usage as data structures, it'd be much appreciated.
Is this a new feature of C++, or something specific to MSVC?
No, as BoBtFish said, the 2003 C++ standard section 9.5 Unions paragraph 1 says:
[...] A union can have member functions (including constructors and destructors), but not virtual (10.3) functions. A union shall not have base classes. A union shall not be used as a base class. An object of a class with a non-trivial constructor (12.1), a non-trivial copy constructor (12.8), a non-trivial destructor (12.4), or a non-trivial copy assignment operator (13.5.3, 12.8) cannot be a member of a union, nor can an array of such objects. If a union contains a static data member, or a member of reference type, the program is ill-formed.
unions do come under section 9 Classes and the grammar for class-key is as follows:
class-key:
class
struct
union
So acts like a class but has many more restrictions. The key restriction being that unions can only have one active non-static member at a time, which is also covered in paragraph 1:
In a union, at most one of the non-static data members can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time. [...]
The wording in the C++11 draft standard is similar so it has not changed too much since 2003.
As for the use of a union, there are two common reasons which are covered from different angles in this previous thread C/C++: When would anyone use a union? Is it basically a remnant from the C only days? to summarize:
To implement your own Variant type, a union gives you the ability to represent all the varying types without wasting memory. This answer to the thread gives a good example.
Type punning but I would read Understanding Strict Aliasing as well since there are many cases where type punning is undefined behavior.
This answer to Unions cannot be used as Base class gives some really great insight into why unions are implemented as they are in C++.
Let's say I have the following structure declaration (simple struct with no constructor).
struct Foo
{
int x;
int y;
int z;
char szData[DATA_SIZE];
};
Now let's say this struct is a member of a C++ class as follows:
class CFoobar
{
Foo _foo;
public:
CFoobar();
};
If I declare CFoobar's constructor as follows:
CFoobar::CFoobar()
{
printf("_foo = {%d, %d, %d}\n", _foo.x, _foo.y,_foo.z);
for (int x = 0; x < 100; x++)
printf("%d\n", _foo.szData[x]);
}
As you would expect, when CFoobar's constructor runs, garbage data gets printed out Obviously, the easy fix is to memset or ZeroMemory &_foo. It's what I've always done...
However, I did notice that if add _foo to the constructor's initialization list with no parameters as follows:
CFoobar::CFoobar()
: _foo()
{
That this appears to zero-out the member variables of _foo. At least that was the case with g++ on linux.
Now here's my question: Is this standard C++, or is this compiler specific behavior?
If it's standard behavior, can someone quote me a reference from an official source? Any "gotchas" in regards to implicit zero-init behavior with more complicated structs and classes?
Yes, this is defined behaviour according to the standard. 12.6.2 [class.base.init] / 3 : "if the expression-list of the mem-initializer is omitted, the base class or member subobject is value-initialized."
Be warned, though, if Foo wasn't a POD-type but still had no user-declared constructor (e.g. it had a std::string type) then some very popular compilers would not correctly value-initialize it.
All compilers that I know of do correctly perform value-initialization of POD members when you use () as the initializer in a constructor initializer-list.
i find it hard to read the standard, but I found it I think:
To value-initialize an object of type T means:
if T is a non-union class type without a user-declared constructor, then every non-static data member and base-
class component of T is value-initialized
Value-initialization for such a class object may be implemented by zero-initializing the object and then calling the default constructor.
Section 8.5
It's the equivalent of float foo = float();
It will zero the object, even if the value representation is not all-bits-zero. I.e. it's even better than memset().
Not sure of the appropriate title, but it stems from this discussion:
Do the parentheses after the type name make a difference with new?
On Visual Studio 2008, when I run the following code:
struct Stan
{
float man;
};
int main()
{
Stan *s1 = new Stan;
Stan *s2 = new Stan();
}
Examining the locals, s1 has an uninitialized float with a random value. s2 is value initialized to 0.
However, if I add a string data member, the float in both instances is uninitialized.
struct Stan
{
std::string str;
float man;
};
However, the string in both instances is initialized. I tried adding other non-POD classes instead of a string, but the latter case only occurs if I add a string data member. I gather that adding a string still keeps it a POD class? If it wasn't a POD class, then it should have value initialized regardless of the parenthesis, right? Any ideas why floats(and other primitive data types for that matter) aren't initialized when I add a string data member?
Adding a string stops the struct from being a POD class because a POD class must be an aggregate class with no members of type non-POD-struct and std::string has (amongst other things) user-declared constructors which makes it a non-POD-struct.
This is a known bug/feature of Visual Studio 2008. It doesn't support C++03 value initialization for non-POD types such as the structure in your second example.
With the struct as in your second example what should happen is the float is not initialized by new Stan but is zero initialized in new Stan().
Types with a user declared default constructor are initialized by calling that constructor in all cases, this happens correctly.
See here and here.
The behavior that you observe is a conforming behavior from the point of view of C++98 specification of the language.
The type in your first example is a so-called POD (Plain Old Data) type. When you apply the () initializer to a POD class type it performs zero-initialization of all data members of the class.
The type in your second example is not a POD type (because of the non-POD member str). When you apply the () initializer to a non-POD class type, it simply calls the class constructor to perform initialization. In your case the implicit [compiler-provided] constructor will properly initialize the str member, but will not do anything for the man member, which is why you see garbage in it.
Again, this is the correct behavior in C++98. It was changed in C++03. In C++03 the () initializer will perform value-initialization. In accordance with the rules of value-initialization, in your second example, the man field should also get zero-initialized in response to () initializer.
See also https://stackoverflow.com/questions/1976185/what-is-the-difference-between-new-myclass-vs-new-myclass for more detailed explanation .