Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

struct initialization / assignment with braces

I have defined a struct as follows:

struct float3 {
float x; 
float y;
float z;

float3 () : x(0), y(0), z(0) {}
float3 (float a, float b, float c) : x(a), y(b), z(c) {}
};

But i have trouble when it comes to understanding the different ways of initializing / assigning values to its members. For instance:

//Initialization
float3 3Dvec = {1.0, 1.0, 1.0};
float3 3Dvec2 {1.0, 1.0, 1.0};
float3 3Dvec3 (1.0, 1.0, 1.0);

//Assignment
3Dvec = {2.0, 2.0, 2.0};
3Dvec = float3 (2.0, 2.0, 2.0);

All of these options do work with -std=c++11. However on an older compiler with -std=c++0x braces initialization / assignment does not work. Is usign braces a bad practice? Which option is better to get used to?

like image 482
Noel Avatar asked Oct 21 '22 07:10

Noel


1 Answers

In C++11, all of these are legal. If you know you'll be working with a C++11-compliant compiler (at least as far as list initialisation is concerned), I'd say it's preferable to use the brace syntax. It's future-proof and unambiguous.

Here's a detailed analysis of the individual statements:

float3 vec3D = {1.0, 1.0, 1.0};

Copy-list-initialisation. Strictly by the book, this creates a temporary float3 by calling its 3-parameter constructor, then initialises vec3D by using the move constructor (or copy constructor, if no move ctor is available), and finally destroys the temporary.

In practice, the temporary creation and move/copy operation will be elided by any non-broken compiler, so there is no inefficiency. However, note that it requires the move/copy constructor to be accessible. You cannot initialise a non-movable, non-copyable class like this, for example.

float3 vec3D2 {1.0, 1.0, 1.0};
float3 vec3D3 (1.0, 1.0, 1.0);

Both of these directly initialise vec3D2 by calling its 3-parameter constructor. I'd say the brace one is the optimal syntax, because it's unambiguous. In this particular case, it does not matter, but sometimes, using parentheses can lead to a (most) vexing parse1.

vec3D = {2.0, 2.0, 2.0};
vec3D = float3 (2.0, 2.0, 2.0);

These are 100% identical, as long as the type of vec3D is float3. Both create a temporary float3 object using its 3-parameter constructor, pass that object to the move (or copy) assignment operator of vec3D, and then destroy the temporary.

I'd say the brace one is better, because it's future proof. If you later rename the class, the brace one will continue to work as is, while the parenthesis one will require a name chaage. Also, if you change the type of vec3D, the brace one will still create an object of vec3D's type, while the second one will keep creating and assigning from a float3 object. It's not possible to say universally, but I'd say the former behaviour is usually preferred.


1 An example of that would be:

float3 x(float3());  // a function
//vs.
float3 y{float3{}};  // a variable
like image 163
Angew is no longer proud of SO Avatar answered Nov 04 '22 00:11

Angew is no longer proud of SO