Initialization: Parenthesis VS. Equals Sign

initialization: parenthesis vs. equals sign

T a( b );

is direct initialization, unless it parses as a function declaration, in which case it's a function declaration.

T a = b;

is copy initialization, which means that it works as if a temporary object is constructed on the right hand side, and that a is then copy constructed or, in C++11 and later, possibly move constructed, from that temporary.

The compiler is free to elide (remove) the temporary+copying/moving whenever it can, but a copy or move constructor, whichever would be logically used, must still be accessible and not explicit.

For example, in C++03 you cannot copy-initialize a std::ostringstream, because it doesn't have a copy constructor. In C++11 you can copy-initialize an ostringstream if the initializer is a temporary, which then results in a logical move construction (which however will usually be elided, optimized away). For example, this copy initialization declaration,

ostringstream s = ostringstream( "blah" );

… doesn't compile as C++03, because in C++03 the copy initialization invokes the class' copy constructor, which doesn't exist. It does however compile as C++11, because in C++11 the copy initialization invokes the move constructor. And while (to maintain its illusion of being a stream) a std::ostringstream can't be directly copied, it can be moved.

Another such difference: in C++03 only the copy initialization syntax supports curly braces initializer, which in C++03 you can use when T is an aggregate type such as a raw array. In C++11 the curly braces notation has been extended and generalized as a uniform initialization syntax, so it can be used also with direct initialization. And so the following direct initialization declaration,

int v[]{ 3, 1, 4, 1, 5, 9, 2, 6, 5, 4 };

… does not compile as C++03, but does compile as C++11 and later.

The = copy initialization syntax is the original initialization syntax from C.

And in C++11 and later, due to move semantics, it can be used in a much wider range of cases than in C++03, such as with a std::ostringstream.

Use curly braces({}) or equal sign(=) when initialize a variable

Which one you choose depends on your own coding style and what you think is best. The most important thing is once you decide which method to use, use that method consistently. Don't switch between methods, it can make it very confusing to read your code. An additional style of variable initialization since C++98 (Called "direct initialization") is:

int variable(1)

But I would advise you against doing this, it doesn't work in certain circumstances, as your book may cover.

My personal style is the one my grandfather who worked on IBM mainframes in the 1960's taught me:

int
Variable1 = 2,
Variable2 = 39,
Variable3 = 45;

bool
Foo = true,
Bar = false;

// etc.

You'll notice I use the "=" sign over curly braces too. This seems to be how the majority of people write their code so me and my Grandfather write it that way to reduce confusion when people read our code. How accepted this method is in a corporate setting or in an organization I do not know, I simply thought it was the most attractive and intuitive style. It also saves a lot of typing.

Does the equal sign make a difference in brace initialization? eg. 'T a = {}' vs 'T a{}'

The only significant difference I know is in the treatment of explicit constructors:

struct foo
{
explicit foo(int);
};

foo f0 {42}; // OK
foo f1 = {42}; // not allowed

This is similar to the "traditional" initialization:

foo f0 (42);  // OK
foo f1 = 42; // not allowed

See [over.match.list]/1.


Apart from that, there's a defect (see CWG 1270) in C++11 that allows brace-elision only for the form T a = {something}

struct aggr
{
int arr[5];
};

aggr a0 = {1,2,3,4,5}; // OK
aggr a1 {1,2,3,4,5}; // not allowed

When should we use parenthesis ( ) vs. initializer { } syntax to initialize objects in C++11?

Scott Meyers tackles this issue in Item 7 of his fantastic "Effective Modern C++". He runs through the differences, pros and cons of both syntaxes, and concludes

There’s no consensus that either approach is better than the other, so my advice is to pick one and apply it consistently.

On the other hand, the C++ Core Guidelines suggest that you prefer the initialiser syntax, so perhaps that's the better default to go for.

Difference between = and {} syntaxes for initializing a variable in C++

int score = 0; performs copy initialization, as the effect, score is initialized to the specified value 0.

Otherwise (if neither T nor the type of other are class types), standard conversions are used, if necessary, to convert the value of other to the cv-unqualified version of T.

int score {}; performs value initialization with braced initializer, which was supported since C++11, as the effect,

otherwise, the object is zero-initialized.

score is of built-in type int, it's zero-initialized at last, i.e. initialized to 0.

If T is a scalar type, the object's initial value is the integral constant zero explicitly converted to T.

Difference between int i(x); and int i = x;

The answer is essentially here.

int i(x); is direct initialization which

Initializes an object from explicit set of constructor arguments.

whereas int i = x; is copy initialization, which

Initializes an object from another object

(The following is probably irrelevant for int, so take it as comment about the difference of the two syntaxes for actual classes: A i(x); vs A i = x;.)

Notice, that both syntaxes can result in a copy constructor being called: if a copy constructor exists for the class A, then the explicit set of constructor arguments that you can provide via direct initialization can consist of exactly one object of class A (which is by the way exactly what happens if x is an int/A in int i(x);/A i(x);.

This is to say that copy initialization is not the only way to construct an object copying it from another object of the same class.

Another point worth noting, in my opinion, is that copy initialization doesn't necessarily mean that copy constructor will be called. If the class A has (beside the copy constructor A(A const&), if you like) the constructor A(int), that is the constructor that will be called if you write A a = 3;.

All this is to say that in my opinion the names of the 6 syntaxes you find listed at the first link I provided are not really telling you what happens; the same thing can happen for more syntaxes, and different things can happen for the same syntax. Those 6 are just names to refer to the syntax of the initialization, not to how the process of initialization happens, because the latter depends on the class of the initialized object and on the initializer object (and on the syntax you pick, sure).

Variable initialization, what's the difference?

C++ supports three basic ways to initialize a variable.
First, we can do copy initialization by using an equals sign:

int width = 5; // copy initialization of value 5 into variable width

This copies the value on the right-hand side of the equals to the variable being created on the left-hand side.
Second, we can do a direct initialization by using parenthesis.

int width( 5 ); // direct initialization of value 5 into variable width

For simple data types (like integers), copy and direct initialization are essentially the same. But for some advanced types, direct initialization can perform better than copy initialization.
Before C++11, direct initialization was recommended over copy initialization in most cases because of the performance boost.

Unfortunately, direct initialization can’t be used for all types of initialization. In an attempt to provide a more consistent initialization mechanism, C++11 added a new syntax for direct initialization called brace initialization (also called uniform initialization) that uses curly braces:

int width{ 5 }; // brace (uniform) initialization of value 5 into variable width

Hope this will help you.

Initialize struct using parentheses instead of curly braces and an equal sign

You can have a user-defined constructor for your struct:

#include <iostream>
struct Matrix2x2 {
int x1;
int x2;
int x3;
int x4;

Matrix2x2(int a, int b, int c, int d)
: x1(a), x2(b), x3(c), x4(d)
{}
};

int main() {
Matrix2x2 m1 = { 1, 2, 3, 4 }; // list initialization
Matrix2x2 res(1, 2, 3, 4); // calls user-defined constructor
}

And pass in the arguments when creating an object (surrounded by parentheses). But you should really prefer the braced initializer instead as it is immune to the most vexing parse:

Matrix2x2 res{ 1, 2, 3, 4 }; // calls user-defined constructor, braced initialization

What are the advantages of list initialization (using curly braces)?

Basically copying and pasting from Bjarne Stroustrup's "The C++ Programming Language 4th Edition":

List initialization does not allow narrowing (§iso.8.5.4). That is:

  • An integer cannot be converted to another integer that cannot hold its value. For example, char
    to int is allowed, but not int to char.
  • A floating-point value cannot be converted to another floating-point type that cannot hold its
    value. For example, float to double is allowed, but not double to float.
  • A floating-point value cannot be converted to an integer type.
  • An integer value cannot be converted to a floating-point type.

Example:

void fun(double val, int val2) {

int x2 = val; // if val == 7.9, x2 becomes 7 (bad)

char c2 = val2; // if val2 == 1025, c2 becomes 1 (bad)

int x3 {val}; // error: possible truncation (good)

char c3 {val2}; // error: possible narrowing (good)

char c4 {24}; // OK: 24 can be represented exactly as a char (good)

char c5 {264}; // error (assuming 8-bit chars): 264 cannot be
// represented as a char (good)

int x4 {2.0}; // error: no double to int value conversion (good)

}

The only situation where = is preferred over {} is when using auto keyword to get the type determined by the initializer.

Example:

auto z1 {99};   // z1 is an int
auto z2 = {99}; // z2 is std::initializer_list<int>
auto z3 = 99; // z3 is an int


Conclusion

Prefer {} initialization over alternatives unless you have a strong reason not to.



Related Topics



Leave a reply



Submit