C++ Struct Initialization Assignment

C++11 will just look, graphically, different than C++03. One of the features that will make that happen is the new way of initializing objects. In this post we will try to write some (rather silly) code, and show by example the new initialization syntax. This is in order to give you a touch and feel of C++11. So, brace yourself for the ride.

We will first create a class representing a two-dimensional point.

class Point { double coefs[2]; public: constexpr Point(); constexpr Point( double x, double y ); constexpr Point( double x ); constexpr double x() { return coefs[0]; } constexpr double y() { return coefs[1]; } };

The class will store the two coëfficients in a two-element array. The reason I chose to use an array is to show how arrays are initialized. We only define a bunch of constructors, and two functions that return the coëfficients. We defined all the functions as just in case we want to initialize some of the objects at compile-time. It was possible to make our class a literal class (a class that can be potentially initialized at compile-time), because we are using simple enough types inside.

Let’s define the default constructor: therein, we want all the coëfficients to be set to zero:

constexpr Point::Point() : coefs{} {};

Do the double braces look funny? You will see more braces in C++11. C++11 just uses braces for initialization. You can still use the old way of initializing objects, but the brace syntax for initialization, as we will see, does offer advantages. Let’s just explain what is going on in the default constructor. The second pair of braces is an empty body of the constructor. The part says that data member is value-initialized. Such value-initialization (even for arrays) is also possible in C++03 with the parenthesized syntax: .


The word value-initialization deserves an explanation, along with the other kinds of initialization.

Zero-initialization. In this case we initialize an object with zeros:

  • for scalar types (, , , pointers, enums), it means initializing them with literal ,
  • for classes (and structs), it means zero-initializing all class sub-objects (members and base classes), we do not call class’es constructor,
  • for arrays, it means zero-initializing each array element.

This type of initialization is used as the first stage for initializing global objects. It is also triggered by the other forms of initializations, that we describe later.

Default-initialization. In this case the initialization is simpler:

  • for classes (and structs), it means calling the default constructor (provided by either the user or the compiler) if it is available (if it is not, we have a compilation error),
  • for arrays, it means default-initializing each array element,
  • for built in types and pointers, we do not initialize.

This initialization takes place when you just type , or when you do not explicitly initialize a sub-object (member or base class) in the initialization list of a constructor. It is faster than zero-initialization, because in most cases you do not have to assign zeros, but less safe, because you have rubbish values in built-in types, which may result in program errors.

Value-initialization. This is typically the most desired type or initialization:

  • for classes, structs and unions with at least one user-defined constructor, it means calling the default constructor, and if it is not accessible, a compile-time error,
  • for classes and structs with no user-defined constructor, it means zero-initialization, followed by a call to default constructor (if it is non-trivial),
  • for arrays, it means value-initializing each array element,
  • for all other cases, we zero-initialize.

This means that value-initializing an array of doubles sets all the elements to value . And this is what we did in our default constructor.

Next, we define a two-argument constructor that initializes with coëfficients and .

constexpr Point::Point( double x, double y ) : coefs{x, y} {}

This is something you cannot do in C++03: we specify all array elements in constructor’s initialization list. Next, let’s define the third constructor. The single will represent coëfficient we will make the other one zero.

constexpr Point::Point( double x ) : coefs{x} {}

This is similar to initializing an array declared in block scope: if the list in braces is too short, the remaining elements are value-initialized.

Next, let’s create a class that represents a line segment identified by two s.

class Segment { Point a, b; public: constexpr Segment( Point a, Point b ) : a{a}, b{b} {} };

Now, let’s define function that will create a ‘unit’ point with being one, and being zero:

constexpr Point unit() { return {1., 0.}; }

No need to specify the name of the type in return statement: we know it already from function signature. Now, let’s write a function that returns coëfficient of a point. we already have a getter for that, but just for the purpose of the exercise:

float getX( Point p ) { return {p.x()}; }

Do the additional braces in return statement change anything? Yes, they make the program fail to compile. This is because initialization with braces is very strict about any narrowing, and the conversion from to is not acceptable. We need to change our function to:

double getX( Point p ) { return {p.x()}; }

Now, we can play a bit with our type .

constexpr Point p{1., 0.}; Point q{}; // default-initialize q q = {2., 1.}; // q is now (2, 1) double x{}; // value-initialize x to 0.0 x = getX(Point(1., 0.)); x = getX(Point{1., 0.}); // same as above x = getX({1., 0.}); // same as above x = Point{5.}.x(); // a temporary x = { Point{5.}.x() }; // detect narrowing

Not that these examples are particularly useful, or natural, but it should give an idea of the syntax. The usage of braces in assignment and function call is worth noting. You can also use braces inside subscript operator.

Now, what is so useful in the brace syntax is that, when you use it, you can easily distinguish initialization from a function call or function definition. Let’s try to create a from two points: one (0, 0), the other (, 0).

Segment seg( Point(), Point(x) );

This sort of works, the program compiles, but you cannot use segment correctly because… it is not a segment. We have declared a function, returning a , and taking another function as the first argument (unnamed), and as the second. There is no such problem with the new syntax:

Segment seg{ Point{}, Point{x} };

Or even shorter:

Segment seg{ {}, {x} };

For an another example, imagine that you are writing a function template, and need to declare an automatic variable of type (a template parameter):

template< typename T > void fun() { T x; // ... }

Variable is default-initialized. This means that, only if is of class type with a user-defined default constructor, will it obtain a determinate value (and in some other cases also). If is an or a pointer, it will not get initialized and we are risking an undefined behavior, in case someone reads it. The following would fix the s and pointers.

T x(0);

But it would likely spoil the case for class types, because the class may have a default constructor, but no converting constructor that can be passed as argument. So we need to write:

T x = T();

This uses value-initialization (and this is what we need); it will work for both situations and is almost fine, except that it will not work for the types without a copy or a move constructor; because here we are making a copy (or move). So we should write:

T x();

But now we have declared a function, rather than an object. If you are familiar with and using Boost libraries, you probably know that you can use utility Value initialized by Fernando Cacciola:

boost::value_initialized<T> x;

Now, the default constructor of the wrapper triggers the value-initialization of the wrapped object. And this is what we wanted; is always value-initialized in any context. Except that it is not anymore. It is now . And although the wrapper tries to do a lot to try to look like (e.g. conversion operators to and ), you can observe some irregularities in the code:

boost::value_initialized<T> x; ++x; // error: no ++ in the wrapper x = T(1); // error: no assignment in the wrapper

Plus, now you require everyone that uses your template to also use Boost libraries. With braces, we can initialize as follows:

T x{};

The new initialization syntax enables you to trigger value-initialization in any context: this was not possible in C++03 because the syntax that would work was interpreted as function declaration.

For the last example, we will see how the new initialization syntax solves an another unresolved problem from C++03: initializing a dynamically allocated array.

int main() { std::unique_ptr<double[]> ptr{ new double[2]{2., 4.} }; assert( ptr[1] == 4. ); }

A word of explanation. We heap-allocate a two-element array of s and initialize it with values 2 and 4. We assign it to a specialization of suitable for storing arrays. is C++11’s better and safer alternative to . Its specialization for arrays calls rather than , and provides rather than and .

And that’s it for this post. Note that we didn’t even mention which allows initializing complex and nested sequence data structures:

std::map< std::string, std::vector<std::complex<double>> > data { {"station1", { {1.0, 0.0}, {1.0, 1.1}, {1.1, 1.2} } }, {"station2", { {1.0, 2.0}, {2.0, 1.2}, {2.3, 3.2} } }, {"stationM", { {2.3, 9.9}, {1.7, 1.3}, {9.8, 4.3} } }, };

The support for the new initialization syntax was added in GCC 4.4. I do not know about other compilers. Some examples also use keyword (not really necessary) which is only available in GCC 4.6.

Like this:

LikeLoading...

Related

This entry was posted in programming and tagged C++11. Bookmark the permalink.

Initialize struct as a pointer

Hello everybody,

I have a little trouble initializing a struct which is declared as a pointer

while this


#include <iostream>

struct teststruct {
bool a, b, c, d;
int num;
}

int main()
{

teststruct myTestStruct = { 0, 1, 1, 1, 60 };

cout << myTestStruct.num << endl;

cout << endl;
return 0;

}



works fine for me I'm having trouble initializing a struct when it is declared as a pointer e.g.



teststruct *myTestStruct;
myTestStruct = { 0, 1, 1, 1, 60 };




Is there a way to do it or am I completly missing something?

Thanks in advance and have a nice day!
- MrBr
first, init the pointer (do a sizeof on myTestStruct now and you'll see that it's 4B(or8B on x64) of size), eg teststruct * myTestStruct = new teststruct;

Than, to acess the teststruct to which you have a pointer, you derefrence your pointer as this:

*myTestStruct

which means that from now on this: (*myTestStruct) from your second example will equal myTeststruct from your second.


*myTestStruct = { 0, 1, 1, 1, 60 }
Hi Gregor,

thx for your quick reply. Unfortunately I've still trouble getting it to work.

From what you wrote and what I understood my code now is:



But it doesn't work. There's a compiler error which says

error C2059: syntax error: '{'
at line 19

Maybe I'm gettig something wrong?
The {} syntax only works when initializing structs and arrays. You can't use it to assign.
It will also not work with new, so don't bother trying.
You are getting something wrong.

A structure object can only use the { ......} value list at initialisation.

This is initialization:


This is NOT initialization:
Thx. That's what I was guessing.

Anyway appreciate your help!
Pointers indicate the memory address where a variable is located, right?

Therefore, the pointer should be pointing to somewhere in memory first, in order to receive a value.



I hope i have helped.
I don't understand what's the point you're trying to convey, but that doesn't compile. You're trying to use the dot operator on a non-object on line 14.
The dot is to indicate the variable "num" in the struct "myTestStruct2".
For example:

Except 'myTestStruct2' is a pointer, not a structure.

EDIT: Oh, and on line 13 you're assigning a structure to a pointer, which is also illegal.
"myTestStruct2" Is a pointer of type "teststruct", then he only can point to a address memory of a variable of type "teststruct", and not other type of any differents primary(int, char, etc) or compound variables (structs).

EDIT: i think what i assigned on line 13 is legal, because the variable and the pointer are of same type("teststruct").
You've been writing C++ for less than a week, haven't you?
Well, i'm a beginner in C++.
I found and I fixed the syntax errors of the above codes, I'm sorry for the confusion I caused.

EDIT: Can you show and explain to me how do that with a code, helios ?

Thank you helios.

"myTestStruct2->num" has the sam effect of "(*myTestStruct2).num" has not ?
Topic archived. No new replies allowed.

0 comments

Leave a Reply

Your email address will not be published. Required fields are marked *