Related
This question seems ancient (since C++98), but a quick search didn't lead me to an answer.
std::size_t n = 100;
std::unique_ptr<int[]> data(new int[n]); // ok, uninitialized
std::unique_ptr<int[]> data(new int[n]()); // ok, value-initialized
std::unique_ptr<int[]> data(new int[n](5)); // not allowed, but why?
What's the rationale behind this restriction, some UDTs cannot be default constructed, so those types cannot be used with new[].
Please don't go astray to suggesting something like std::vector or just say that's how the standard defines it, everyone knows that, but I want to know the reason why new T[n](arg...) is forbidden by the standard.
The first part of the answer to "why is it forbidden" is almost tautological: because it is not allowed by the standard. I know you probably don't like such an answer, but that's the nature of the beast, sorry.
And why should it be allowed anyway? What would it mean? In your very very very simple case, initializing every int with a specific value is fairly reasonable. But then again, for normal (statically allocated) array initialization, the rule is that each element in the right hand side {} is passed to an element of the left hand side array, with extra elements getting default-initialization treatment. Ie,
int data[n] = {5};
would only initialize the first element with 5.
But let's look at another example, which isn't even very contrived, which shows that what you ask for doesn't really make a lot of sense in a general context.
struct Foo {
int a,b,c,d;
Foo(int a=0, int b=0, int c=0, int d=0)
: a(a), b(b), c(c), d(d) {}
};
...
Foo *f = new Foo[4](1,2,3,4); // <-- what does this mean?!?!
Should there be four Foo(1,2,3,4)s? Or [Foo(1,2,3,4), Foo(), Foo(), Foo()]? Or maybe [Foo(1), Foo(2), Foo(3), Foo(4)]? Or why not [Foo(1,2,3), Foo(4), Foo(), Foo()]? What if one of Foo's arguments was rvalue reference or something? There are just soooo many cases in which there is no obvious Right Thing that the compiler should do. Most of the examples I just gave have valid use cases, and there isn't one that's clearly better than the others.
PS: You can achieve what you want with eg
std::vector<int> data(n, 5);
some UDTs don't even have a default ctor, so those types cannot be used with new[]
I'm not sure what you mean by this. E.g. int does not have a default constructor. However, you can initialize it as new int(3) or as new int[n](), as you already know. The event that takes place here is called initialization. Initialization can be carried out by constructors, but that's just a specific kind of initialization applicable to class types only. int is not a class type and constructors are completely inapplicable to int. So, you should not be even mentioning constructors with regard to int.
As for new int[n](5)... What did you expect to happen in this case? C++ does not support such syntax for array initialization. What did you want it to mean? You have n array elements and only one initializer. How are you proposing to initialize n array elements and only one initializer? Use value 5 to initialize each array element? But C++ never had such multi-initialization. Even the modern C++ doesn't.
You seem to have adopted this "multi-initialization" interpretation of new int[n](5) syntax as the one and only "obviously natural" way for it to behave. However, this is not necessarily that clear-cut. Historically C++ language (and C language) followed a different philosophy with regard to initializers that are "smaller" or "shorter" than the aggregate being initialized. Historically the language used the explicitly specified initializers to initialize the sub-objects at the beginning of the aggregate, while the rest of the sub-objects got default-initialized (sticking to C++98 terminology). From this point of view, you can actually see the () initializer in new int[n]() not as your "multi-initializer", but rather as an initializer only for the very first element of the array. Meanwhile, the rest of the elements get default-initialized (producing the same effect as () would). Granted, one can argue that the above logic usually applies to { ... } initializers, not to (...) initializers, but nevertheless this general design principle is present in the language.
It's not clear what int[n](5) would even mean. int[5]{1,2,3,4,5} is perfectly well-defined, however.
I'm going to assume you mean for int[n](...) to construct each array element in the same way with the given arguments. Your use case for such a syntax is for data types without a default constructor, but I posit that you don't actually solve that use case: that for many (most?) arrays of such types, each object needs to be constructed differently.
The original expectation is to allow new T[n](arg…) to call T(arg…) to initialize each element.
It turns out that people don't even agree on what new T[n](arg…) would mean.
I gather some good points from the ansnwers and comments, here's the summary:
Inconsistent meaning. parenthesized initializer is used to initialize the object, in case of an array, the only viable one is () which default initializes the array and its elements. Give T[n](arg…) a new meaning will conflict with the current meaning of parenthesized initializer.
No general way to channel the args. Consider a type T with ctor T(int, Ref&, Rval&&), and the usage new T[n](++i, ref, Rval{}). If the args is supplied literally (i.e. call T(++i, ref, Rval{}) for each), ++i will be called multiple times. If the args is supplied through some temporaries, how can you decide ref will pass by reference, while Rval{} will pass as prvalue?
In short, the syntax seems plausible but doesn't actually make sense and is not generally implementable.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is there a difference in C++ between copy initialization and direct initialization?
I just started to learn C++.
To initialize a variable with a value, I came across
int a = 0;
and
int a(0);
This confuses me a lot. May I know which is the best way?
int a = 0; and int a(0); make no difference in the machine generated code. They are the same.
Following is the assembly code generated in Visual Studio
int a = 10; // mov dword ptr [a],0Ah
int b(10); // mov dword ptr [b],0Ah
They're both the same, so there really is no one "best way".
I personally use
int a = 0;
because I find it more clear and it's more widely used in practice.
This applies to your code, where the type is int. For class-types, the first is copy-initialization, whereas the other is direct-initialization, so in that case it would make a difference.
There's no "best" way. For scalar types (like int in your example) both forms have exactly the same effect.
The int a(0) syntax for non-class types was introduced to support uniform direct-initialization syntax for class and non-class types, which is very useful in type-independent (template) code.
In non-template code the int a(0) is not needed. It is completely up to you whether you want to use the int a(0) syntax, or prefer to stick to more traditional int a = 0 syntax. Both do the same thing. The latter is more readable, in my opinion.
From a practical point of view: I would only use int a = 0;.
The int a(0) may be allowed but never used in practice in itself.
I think it should not bother you on your level, but let us go further.
Let's say that a is a class, not an int.
class Demo{
public:
Demo(){};
Demo(int){};
};
Demo a;
Demo b(a);
Demo c = a; // clearly expressing copy-init
In this example both b(a) and c=a do the same, and I would discourage you using the fist solution. My reason is, that is looks similar to c(2) which is a construction from arguments.
There are only two valid uses of this bracket-style initialization:
initialization lists (Demo(int i):data(i){} if Demo has an int data member data),
new's: Demo *p=new Demo(a); // copy constructing a pointer
It’s that simple. (Well, almost — there are a few things you can’t name your variables, which we’ll talk about in the next section)
You can also assign values to your variables upon declaration. When we assign values to a variable using the assignment operator (equals sign), it’s called an explicit assignment:
int a= 5; // explicit assignment
You can also assign values to variables using an implicit assignment:
int a(5); // implicit assignment
Even though implicit assignments look a lot like function calls, the compiler keeps track of which names are variables and which are functions so that they can be resolved properly.
In textbooks and literature, one is direct initialization and the other is copy initialization. But, in terms of machine code, there is no difference.
The difference is that () initialization is when you explicitly want it to take one parameter only, e.g:
You can:
int a = 44 + 2;
but you can't:
int a(44) + 2;
I understand from the answer to this question that values of global/static uninitialized int will be 0. The answer to this one says that for vectors, the default constructor for the object type will be called.
I am unable to figure out - what happens when I have vector<int> v(10) in a local function. What is the default constructor for int? What if I have vector<int> v(10) declared globally?
What I am seeing is that vector<int> v(10) in a local function is resulting in variables being 0 - but I am not sure if that is just because of my compiler or is the fixed expected behaviour.
The zero initialization is specified in the standard as default zero initialization/value initialization for builtin types, primarily to support just this type of case in template use.
Note that this behavior is different from a local variable such as int x; which leaves the value uninitialized (as in the C language that behavior is inherited from).
It is not undefined behaviour, a vector automatically initialises all its elements. You can select a different default if you want.
The constructor is:
vector( size_type, T t = T() )
and for int, the default type (returned by int()) is 0.
In a local function this:
int x;
is not guaranteed to initialise the variable to 0.
int x = int();
would do so.
int x();
sadly does neither but declares a function.
The constructor you are using actually takes two arguments, the second of which is optional. Its declaration looks like this:
explicit vector(size_type n, const T& value = T())
The first argument is the number of elements to create in the vector initially; the second argument is the value to copy into each of those elements.
For any object type T, T() is called "value initialization." For numeric types, it gives you 0. For a class type with a default constructor, it gives you an object that has been default constructed using that constructor.
For more details on the "magic parentheses," I'd recommend reading Michael Burr's excellent answer to the question "Do the parentheses after the type name make a difference with new?" It discusses value initialization when used with new specifically, but for the most part is applicable to value initialization wherever else it can be used.
By default, vector elements are zero-initialized and not default-initialized. Those are two different but related concepts:
zero-initialization is what is done for static objects not having an explicit initialization and what is done for a member given in the initialized list with an initializer of (). For basic types, the value used is 0 converted to the type.
default-initialization is what is done for not explicitly initialized non static variables and members. For basic types it stay uninitialized.
(And C++0X introduces value-initialization which is still different).
As mentioned by others, what happens is the zero initialization kicks in. I actually use that a lot in my code (outside of vectors and other classes):
some_type my_var = some_type();
This allows me to make sure that my variables are always properly initialized since by default C/C++ do not initialize basic types (char, short, int, long, float, double, etc.)
Since C++11, you also can do so in your class definitions:
class MyClass
{
...
int my_field_ = 123; // explicit initialization
int your_field_ = int(); // zero initialization
};
For vectors, the std library uses T(). Whatever T() is, it will use that default initialization. For a class, it calls the default constructor. For a basic type, it uses zero ('\0', 0, 0.0f, 0.0, nullptr`).
As mentioned by James McNellis and Nawaz, it is possible to set the value used to initialize the vector as in:
std::vector<int> foo(100, 1234);
That feature is also available when you resize your vector (if the vector shrinks, the default value is ignored):
foo.resize(200, 1234);
So that way you can have a default initialization value. However, it's a be tricky since you have to make sure that all your definitions and resize() calls use that default value. That's when you want to write your own class which ensures that the default value is always passed to the vector functions.
However, if you want to have a way to auto-initialize to a specific value, you can mix both features this way:
struct my_value {
int v = 123;
};
std::vector<my_value> foo(100);
// here foo[n].v == 123 for n in [0, 100)
This is my preferred way of dealing with this issue (i.e. if I don't want zero by default). It's an extra .v, but much less prone to mistakes and you don't need to know of the default value when you create a vector of my_value.
Also, for those who think this will be slow, it won't. The struct is like syntactic sugar as far as C++ is concerned. One optimized, it will be exactly the same as a simple std::vector<int> foo(100, 123).
The default initialization for an int type is to initialize it to 0.
This is true of most (if not all) primitive types: char will initialize to (char)0 (or '\0' if you prefer), float will initialize to 0.0f, and any pointer initializes to NULL. For other types, the parameterless constructor is invoked.
In general, the default initialization should happen pretty much whenever you aren't able to specify a constructor (or choose not to).
This question already has answers here:
Closed 13 years ago.
Possible Duplicate:
Is there a difference in C++ between copy initialization and assignment initialization?
I am new to C++, I seldom see people using this syntax to declare and initialize a variable:
int x(1);
I tried, the compiler did not complain and the output is the same as int x=1, are they actually the same thing?
Many thanks to you all.
Yes, for built in types int x = 1; and int x(1); are the same.
When constructing objects of class type then the two different initialization syntaxes are subtly different.
Obj x(y);
This is direct initialization and instructs the compiler to search for an unambiguous constructor that takes y, or something that y can be implicitly converted to, and uses this constructor to initialize x.
Obj x = y;
This is copy initialization and instructs the compiler to create a temporary Obj by converting y and uses Obj's copy constructor to initalize x.
Copy initalization is equivalent to direct initialization when the type of y is the same as the type of x.
For copy initalization, because the temporary used is the result of an implicit conversion, constructors marked explicit are not considered. The copy constructor for the constructed type must be accessible but the copy itself may be eliminated by the compiler as an optmization.
For POD-types, both statements are identical.
I'm no C++ expert, but if it gives the same result, does it matter? I guess if you were REALLY interested, you could compile (but not assemble) your code and have a look at what the difference is.
Edit: As has been mentioned elsewhere, they really are the same for builtin types.
Where I work, people mostly think that objects are best initialised using C++-style construction (with parentheses), whereas primitive types should be initialised with the = operator:
std::string strFoo( "Foo" );
int nBar = 5;
Nobody seems to be able to explain why they prefer things this way, though. I can see that std::string = "Foo"; would be inefficient because it would involve an extra copy, but what's wrong with just banishing the = operator altogether and using parentheses everywhere?
Is it a common convention? What's the thinking behind it?
Initializing variables with the = operator or with a constructor call are semantically the same, it's just a question of style. I prefer the = operator, since it reads more naturally.
Using the = operator usually does not generate an extra copy - it just calls the normal constructor. Note, however, that with non-primitive types, this is only for initializations that occur at the same time as the declarations. Compare:
std::string strFooA("Foo"); // Calls std::string(const char*) constructor
std::string strFoo = "Foo"; // Calls std::string(const char*) constructor
// This is a valid (and standard) compiler optimization.
std::string strFoo; // Calls std::string() default constructor
strFoo = "Foo"; // Calls std::string::operator = (const char*)
When you have non-trivial default constructors, the latter construction can be slightly more inefficient.
The C++ standard, section 8.5, paragraph 14 states:
Otherwise (i.e., for the remaining copy-initialization cases), a temporary is created. User-defined conversion sequences that can convert from the source type to the destination type or a derived class thereof are enumerated (13.3.1.4), and the best one is chosen through overload resolution (13.3). The user-defined conversion so selected is called to convert the initializer expression into a temporary, whose type is the type returned by the call of the user-defined conversion function, with the cv-qualifiers
of the destination type. If the conversion cannot be done or is ambiguous, the initialization is ill-formed. The object being initialized is then direct-initialized
from the temporary according to the rules above.87) In certain cases, an implementation is permitted to eliminate the temporary by initializing the object directly; see 12.2.
Part of section 12.2 states:
Even when the creation of the temporary object is avoided, all the semantic restrictions must be respected as if the temporary object was created. [Example:
even if the copy constructor is not called, all the semantic restrictions, such as accessibility (11), shall be satisfied. ]
I just felt the need for another silly litb post.
string str1 = "foo";
is called copy-initialization, because what the compiler does, if it doesn't elide any temporaries, is:
string str1(string("foo"));
beside checking that the conversion constructor used is implicit. In fact, all implicit conversions are defined by the standard in terms of copy initialization. It is said that an implicit conversion from type U to type T is valid, if
T t = u; // u of type U
is valid.
In constrast,
string str1("foo");
is doing exactly what is written, and is called direct initialization. It also works with explicit constructors.
By the way, you can disable eliding of temporaries by using -fno-elide-constructors:
-fno-elide-constructors
The C++ standard allows an implementation to omit creating a temporary which
is only used to initialize another object of the same type. Specifying this
option disables that optimization, and forces G++ to call the copy constructor
in all cases.
The Standard says there is practically no difference between
T a = u;
and
T a(u);
if T and the type of u are primitive types. So you may use both forms. I think that it's just the style of it that makes people use the first form rather than the second.
Some people may use the first in some situation, because they want to disambiguate the declaration:
T u(v(a));
migh look to someone as a definition of a variable u that is initialized using a temporary of a type v that gets a parameter for its constructor called a. But in fact, what the compiler does with that is this:
T u(v a);
It creates a function declaration that takes a argument of type v, and with a parameter called a. So people do
T u = v(a);
to disambiguate that, even though they could have done
T u((v(a)));
too, because there are never parentheses around function parameters, the compiler would read it as a variable definition instead of a function declaration too :)
Unless you've proven that it matters with respect to performance, I wouldn't worry about an extra copy using the assignment operator in your example (std::string foo = "Foo";). I'd be pretty surprised if that copy even exists once you look at the optimized code, I believe that will actually call the appropriate parameterized constructor.
In answer to your question, yes, I'd say that it's a pretty common convention. Classically, people have used assignment to initialize built-in types, and there isn't a compelling reason to change the tradition. Readability and habit are perfectly valid reasons for this convention given how little impact it has on the ultimate code.
You will probably find that code such as
std::string strFoo = "Foo";
will avoid doing an extra copy and compiles to the same code (a call of a single-argument constructor) as the one with parentheses.
On the other hand, there are cases where one must use parentheses, such as a constructor member initialisation list.
I think the use of = or parentheses to construct local variables is largely a matter of personal choice.
Well, who knows what they think, but I also prefer the = for primitive types, mainly because they are not objects, and because that's the "usual" way to initialize them.
But then just to confuse you even more you initialize primitives in the initialization list using object syntax.
foo::foo()
,anInt(0)
,aFloat(0.0)
{
}
It's an issue of style. Even the statement that "std::string = "Foo"; would be inefficient because it would involve an extra copy" is not correct. This "extra copy" is removed by the compiler.
I believe that is more of a habit, very few objects could be initialized using = , the string is one of them. It's also a way of doing what you said "using parenthesis everywhere (that the language allows you to use it)"
One argument that one could make for:
std::string foo("bar");
Is that it keeps things the same even if the argument count changes, i.e.:
std::string foo("bar", 5);
Doesn't work with a '=' sign.
Another thing is that for many objects a '=' feels unnatural, for example say you have a Array class where the argument gives the length:
Array arr = 5;
Doesn't feel good, since we don't construct an Array with the value 5, but with length 5:
Array arr(5);
feels more natural, since you are constructing an object with the given parameter, not just copying a value.