The compiler seems to have no problem with this. Can I safely assume that any object I create of this type will have these defaults values?
struct ColorProperties
{
bool colorRed = true;
bool colorBlue = false;
bool isRectangle = true;
};
ColorProperties myProperties;
Will myProperties automatically contain element values as noted by the struct?
Yes, you can. It's C++11 feature. Really it's equal to
struct ColorProperties {
ColorProperties()
: colorRed(true), colorBlue(false), isRectangle(true)
{}
//
};
You can read about this proposal here
Quotes from standard.
n3376 12.6.2/8
In a non-delegating constructor, if a given non-static data member or base class is not designated by a
mem-initializer-id (including the case where there is no mem-initializer-list because the constructor has no
ctor-initializer) and the entity is not a virtual base class of an abstract class (10.4), then
— if the entity is a non-static data member that has a brace-or-equal-initializer, the entity is initialized
as specified in 8.5;
struct A {
A();
};
struct B {
B(int);
};
struct C {
C() { }
A a;
const B b; // error: B has no default constructor
int i; // OK: i has indeterminate value
int j = 5; // OK: j has the value 5
};
Related
I have a struct that contains multiple members.
these members should be constructed using another member.
Is accessing this other member for the initialization of the members valid, or am I invoking UB this way?
struct Data {
int b;
};
struct Bar {
Bar(Data& d): a(d.b){
}
int a;
};
struct Foo {
Data data;
Bar b;
};
int main() {
Foo f {.data = Data(), .b = Bar(f.data)}; // b is constructed using f.data!
}
https://godbolt.org/z/fajPjo6oa
Members are initialized in the order they are declared in the struct/class and you can validly reference other members during initialization, as long as they have already been initialized at that point.
This holds regardless of how initialization is performed.
OK, member variables can be used to initialize other member variables in an initialization list (with care taken about the initialization order etc). What about member functions? To be specific, is this snippet legal according to the C++ standard?
struct foo{
foo(const size_t N) : N_(N), arr_(fill_arr(N)) {
//arr_ = fill_arr(N); // or should I fall back to this one?
}
std::vector<double> fill_arr(const size_t N){
std::vector<double> arr(N);
// fill in the vector somehow
return arr;
}
size_t N_;
std::vector<double> arr_;
// other stuff
};
Yes, your use of member function in initialization list is valid and complies with the standard.
Data members are initialized in the order of their declaration (and that's the reason why they should appear in the initialization list in the order of their declaration - the rule that you followed in your example). N_ is initialized first and you could have passed this data member to fill_arr. fill_arr is called before constructor but because this function does not access uninitialized data members (it does not access data members at all) its call is considered safe.
Here are some relevant excepts from the latest draft (N3242=11-0012) of the C++ standard:
§ 12.6.2.13: Member functions (including virtual member functions,
10.3) can be called for an object under construction.(...) However, if these operations are performed in a ctor-initializer (or in a function
called directly or indirectly from a ctor-initializer) before all the
mem-initializers for base classes have completed, the result of the
operation is undefined. Example:
class A { public: A(int); };
class B : public A {
int j;
public:
int f();
B() : A(f()), // undefined: calls member function
// but base A not yet initialized
j(f()) { } // well-defined: bases are all initialized
};
class C {
public:
C(int);
};
class D : public B, C {
int i;
public:
D() : C(f()), // undefined: calls member function
// but base C not yet initialized
i(f()) { } // well-defined: bases are all initialized
};
§12.7.1: For an object with a non-trivial constructor, referring to
any non-static member or base class of the object before the
constructor begins execution results in undefined behavior. Example
struct W { int j; };
struct X : public virtual W { };
struct Y {
int *p;
X x;
Y() : p(&x.j) { // undefined, x is not yet constructed
}
};
While initializing objects in the initialization list, the object is not yet fully constructed.
If those function tries to access the part of the object which is not yet constructed then that is a undefined behavior else its fine.
see this answer.
Consider the following code:
class A
{
private:
struct B { private: int i; friend class A; };
public:
static void foo1()
{
B b;
b.i = 0;
}
static void foo2()
{
B b = {0};
}
};
Why does foo1 work but not foo2? Is not the struct initializer constructor visible for class A? Is there anyway to make this work in C++11?
(Note, removing the private makes foo2 working.)
Why does foo1 work but not foo2? Is not the struct initializer constructor visible for class A?
B b = {0};
Does not work because B is not an Aggregate. And it is not an Aggregate because it has an non-static private data member. If you remove the private specifier, B becomes an Aggregate and hence can be initialized in this manner.
C++03 Standard 8.5.1 Aggregates
Para 7:
If there are fewer initializers in the list than there are members in the aggregate, then each member not explicitly initialized shall be value-initialized (8.5).
[Example:
struct S { int a; char* b; int c; };
S ss = { 1, "asdf" };
initializes ss.a with 1, ss.b with "asdf", and ss.c with the value of an expression of the form int(), that is,0. ]
C++03 standard 8.5.1 §1:
An aggregate is an array or a class (clause 9) with no user-declared
constructors (12.1), no private or protected non-static data members (clause 11),
no base classes (clause 10), and no virtual functions (10.3).
OK, member variables can be used to initialize other member variables in an initialization list (with care taken about the initialization order etc). What about member functions? To be specific, is this snippet legal according to the C++ standard?
struct foo{
foo(const size_t N) : N_(N), arr_(fill_arr(N)) {
//arr_ = fill_arr(N); // or should I fall back to this one?
}
std::vector<double> fill_arr(const size_t N){
std::vector<double> arr(N);
// fill in the vector somehow
return arr;
}
size_t N_;
std::vector<double> arr_;
// other stuff
};
Yes, your use of member function in initialization list is valid and complies with the standard.
Data members are initialized in the order of their declaration (and that's the reason why they should appear in the initialization list in the order of their declaration - the rule that you followed in your example). N_ is initialized first and you could have passed this data member to fill_arr. fill_arr is called before constructor but because this function does not access uninitialized data members (it does not access data members at all) its call is considered safe.
Here are some relevant excepts from the latest draft (N3242=11-0012) of the C++ standard:
§ 12.6.2.13: Member functions (including virtual member functions,
10.3) can be called for an object under construction.(...) However, if these operations are performed in a ctor-initializer (or in a function
called directly or indirectly from a ctor-initializer) before all the
mem-initializers for base classes have completed, the result of the
operation is undefined. Example:
class A { public: A(int); };
class B : public A {
int j;
public:
int f();
B() : A(f()), // undefined: calls member function
// but base A not yet initialized
j(f()) { } // well-defined: bases are all initialized
};
class C {
public:
C(int);
};
class D : public B, C {
int i;
public:
D() : C(f()), // undefined: calls member function
// but base C not yet initialized
i(f()) { } // well-defined: bases are all initialized
};
§12.7.1: For an object with a non-trivial constructor, referring to
any non-static member or base class of the object before the
constructor begins execution results in undefined behavior. Example
struct W { int j; };
struct X : public virtual W { };
struct Y {
int *p;
X x;
Y() : p(&x.j) { // undefined, x is not yet constructed
}
};
While initializing objects in the initialization list, the object is not yet fully constructed.
If those function tries to access the part of the object which is not yet constructed then that is a undefined behavior else its fine.
see this answer.
I have the following class definitions in c++:
struct Foo {
int x;
char array[24];
short* y;
};
class Bar {
Bar();
int x;
Foo foo;
};
and would like to initialize the "foo" struct (with all its members) to zero in the initializer of the Bar class. Can this be done this way:
Bar::Bar()
: foo(),
x(8) {
}
... ?
Or what exactly does the foo(x) do in the initializer list?
Or is the struct even initialized automatically to zero from the compiler?
First of all, you should (must !) read this c++ faq regarding POD and aggregates. In your case, Foo is indeed a POD class and foo() is a value initialization :
To value-initialize an object of type
T means:
if T is a class type (clause 9) with a user-declared 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 non-union class type without a user-declared constructor, then every non-static data member and base-class component of T is value-initialized;
if T is an array type, then each element is value-initialized;
otherwise, the object is zero-initialized
So yes, foo will be zero-initialized. Note that if you removed this initialization from Bar constructor, foo would only be default-initialized :
If no initializer is specified for an
object, and the object is of (possibly
cv-qualified) non-POD class type (or
array thereof), the object shall be
default-initialized; if the object is
of const-qualified type, the
underlying class type shall have a
user-declared default constructor.
Otherwise, if no initializer is
specified for a nonstatic object, the
object and its subobjects, if any,
have an indeterminate initial
value;
In standard C++ you need to make a ctor for Foo.
struct Foo {
Foo(int const a, std::initializer_list<char> const b, short* c)
: x(a), y(c) {
assert(b.size() >= 24, "err");
std::copy(b.begin(), b.begin() + 24, array);
}
~Foo() { delete y; }
int x;
char array[24];
short* y;
};
class Bar {
Bar() : x(5), foo(5, {'a', 'b', ..., 'y', 'z'},
new short(5)) { }
private:
int x;
Foo foo;
};
In C++0x you may use uniform initialization list, but still you need dtor for Foo:
class Bar {
Bar() : x(5), foo{5, new char[24]{'a', 'b', ..., 'y', 'z'},
new short(5)} { }
~Bar() { delete[] foo.array; delete foo.y;}
}
private:
int x;
Foo foo;
};
To default initialize foo (as Bar() : foo(), x(8) { }) you need to give Foo a default ctor.