What's the Difference Between Parentheses and Braces in C++ When Constructing Objects

What's the difference between parentheses and braces in c++ when constructing objects

For S, they have the same effect. Both invoke the constructor S::S(int) to initialize the objects.

S s2{12}; is regared as list initialization (since C++11); S is not an aggregate type and not std::initializer_list, and has no constructor taking std::initializer_list, then

If the previous stage does not produce a match, all constructors of T participate in overload resolution against the set of arguments that consists of the elements of the braced-init-list, with the restriction that only non-narrowing conversions are allowed.

and you thought that

I think {} is only can be used for an array or initializer_list type.

This is not true. The effect of list-initialization is that, e.g. if S is an aggregate type, then aggregate initialization is performed; if S is a specialization of std::initializer_list, then it's initialized as a std::initializer_list; if S has a constructor taking std::initializer_list, then it will be preferred to be used for initialization. You can refer to the page linked for more precise details.

PS: S s1(12); performs direct initialization.

Parenthesis vs curly braces

I added some additional code to show what is actually happening.

#include<iostream>
using namespace std;

class test
{
public:
int a,b;

test()
{
cout << "default constructor" << endl;
}

~test()
{
cout << "destructor" << endl;
}

test(int x,int y):a(x),b(y)
{
cout << "parameterized constructor" << endl;
}

test& operator=(const test& rhs)
{
a = rhs.a;
b = rhs.b;
cout << "assignment operator" << endl;
return *this;
}

};

int main()
{

test t;
cout << t.a << endl;
//t=(2,3);->gives error
t={2,3}; //calls parameterized constructor
cout << t.a << endl;
}

Output:

default constructor
4197760
parameterized constructor
assignment operator
destructor
2
destructor

So the statement t={2,3}; is actually constructing a new test object using the parameterized constructor, calling the assignment operator to set t to be equal to the new, temporary test object, and then destroying the temporary test object. It's equivalent to the statement t=test(2,3).

Difference between creating object with () or without

The other answers correctly state that the parentheses version is actually a function declaration. To understand it intuitively, suppose you wrote MainGUIWindow f(); Looks more like a function, doesn't it? :)
The more interesting question is what is the difference between

MainGUIWindow* p = new MainGUIWindow;

and

MainGUIWindow* p = new MainGUIWindow();

The version with parentheses is called value-initialization, whereas the version without is called default-initialization. For non-POD classes there is no difference between the two. For POD-structs, however, value-initialization involves setting all members to 0,

my2c

Addition: In general, if some syntactic construct can be interpreted both as a declaration and something else, the compiler always resolves the ambiguity in favor of the declaration.

C++11 Difference in Constructors (Braces)

Ways one and three call the default constructor.

MyClass c3{};

Is a new initialization syntax called uniform initialization. This is called default brace initialization. However:

MyClass c2();

Declares a function c2 which takes no parameters with the return type of MyClass.

Difference between declaring a C++ object with/without braces

Test obj();

declares a function named obj that takes no parameters and returns an object of type Test. It does not create an object obj of type Test with the default constructor.

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.

C# List definition, parentheses vs curly braces

The use of curly braces { } is called a collection initializer. For types that implement IEnumerable the Add method would be invoked normally, on your behalf:

List<string> myList2 = new List<string>() { "one", "two", "three" };

Empty collection initializers are allowed:

List<string> myList2 = new List<string>() { };

And, when implementing an initializer, you may omit the parenthesis () for the default constructor:

List<string> myList2 = new List<string> { };

You can do something similar for class properties, but then it's called an object initializer.

var person = new Person
{
Name = "Alice",
Age = 25
};

And its possible to combine these:

var people = new List<Person>
{
new Person
{
Name = "Alice",
Age = 25
},
new Person
{
Name = "Bob"
}
};

This language feature introduced in C# 3.0 also supports initializing anonymous types, which is especially useful in LINQ query expressions:

var person = new { Name = "Alice" };

They also work with arrays, but you can further omit the type which is inferred from the first element:

var myArray = new [] { "one", "two", "three" };

And initializing multi-dimensional arrays goes something like this:

var myArray = new string [,] { { "a1", "b1" }, { "a2", "b2" }, ... };

Update

Since C# 6.0, you can also use an index initializer. Here's an example of that:

var myDictionary = new Dictionary<string, int>
{
["one"] = 1,
["two"] = 2,
["three"] = 3
};


Related Topics



Leave a reply



Submit