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 orinitializer_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
Two Classes That Refer to Each Other
Speed Difference Between If-Else and Ternary Operator in C...
Does One Double Promote Every Int in the Equation to Double
Efficiently Convert Between Hex, Binary, and Decimal in C/C++
Static Variable in the Class Declaration or Definition
C++ Virtual Override Functions with Same Name
How to Use Unicode Range in C++ Regex
What Does -Fpic Mean When Building a Shared Library
Creating JSON Arrays in Boost Using Property Trees
How Copy from One Stringstream Object to Another in C++
Why Can't I Access a Protected Member from an Instance of a Derived Class
How to Cheaply Assign C-Style Array to Std::Vector
Accessing Static Member Through Invalid Pointer: Guaranteed to "Work"
Does C++11 Allow Dollar Signs in Identifiers