This question already has answers here:
What are the advantages of list initialization (using curly braces)?
(5 answers)
Closed 1 year ago.
When I am reading The C++ Programming Language 4th Edition, to initialize a variable, the author said it's better to use {} than = to initialize a variable:
But I see that there are more people use = than {}.
So which method is a good principle to persist? = or {}?
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.
Before any other comes up with the silly idea that
T a = b ( where b is type of T ) ends up in an assignment operator call,
Lets clear it, in C++ and in any object orient language, assignment operator can not be used on a not yet created object.
This is initialization, and this was an invoke of copy constructor all the time, was not matter of C++ version.
In this case the '=' is just a syntactic sugar.
See the Reference in the Explanation section:
The copy constructor is called whenever an object is initialized (by direct-initialization or copy-initialization) from another object of the same type (unless overload resolution selects a better match or the call is elided), which includes
initialization: T a = b; or T a(b);, where b is of type T;
One reason the book suggests using an initializer is that it becomes the initial value.
When using the assignment '=', in some cases you end up constructing the object which gives it an initial value and then the code uses the assignment operator of the class type to change the initial value, so it is less efficient. This is only in some cases, depending on the constructors available and so on.
However, in most cases modern compilers can optimize it to make it the same thing. So it's not worth worrying about.
One problem with C++ is there is always several ways to do the same thing, no matter how simple that thing may be.
Related
Suppose I have a class like this:
class Foo
{
public:
Foo(int something) {}
};
And I create it using this syntax:
Foo f{10};
Then later I add a new constructor:
class Foo
{
public:
Foo(int something) {}
Foo(std::initializer_list<int>) {}
};
What happens to the construction of f? My understanding is that it will no longer call the first constructor but instead now call the init list constructor. If so, this seems bad. Why are so many people recommending using the {} syntax over () for object construction when adding an initializer_list constructor later may break things silently?
I can imagine a case where I'm constructing an rvalue using {} syntax (to avoid most vexing parse) but then later someone adds an std::initializer_list constructor to that object. Now the code breaks and I can no longer construct it using an rvalue because I'd have to switch back to () syntax and that would cause most vexing parse. How would one handle this situation?
What happens to the construction of f? My understanding is that it will no longer call the first constructor but instead now call the init list constructor. If so, this seems bad. Why are so many people recommending using the {} syntax over () for object construction when adding an initializer_list constructor later may break things silently?
On one hand, it's unusual to have the initializer-list constructor and the other one both be viable. On the other hand, "universal initialization" got a bit too much hype around the C++11 standard release, and it shouldn't be used without question.
Braces work best for like aggregates and containers, so I prefer to use them when surrounding some things which will be owned/contained. On the other hand, parentheses are good for arguments which merely describe how something new will be generated.
I can imagine a case where I'm constructing an rvalue using {} syntax (to avoid most vexing parse) but then later someone adds an std::initializer_list constructor to that object. Now the code breaks and I can no longer construct it using an rvalue because I'd have to switch back to () syntax and that would cause most vexing parse. How would one handle this situation?
The MVP only happens with ambiguity between a declarator and an expression, and that only happens as long as all the constructors you're trying to call are default constructors. An empty list {} always calls the default constructor, not an initializer-list constructor with an empty list. (This means that it can be used at no risk. "Universal" value-initialization is a real thing.)
If there's any subexpression inside the braces/parens, the MVP problem is already solved.
Retrofitting classes with initializer lists in updated code is something that sounds like it will be a common thing to happen. So people start using {} syntax for existing constructors before the class is updated, and we want to automatically catch any old uses, especially those used in templates where they may be overlooked.
If I had a class like vector that took a size, then arguably using {} syntax is "wrong", but for the transition we want to catch that anyway. Constructing C c1 {val} means take some (one, in this case) values for the collection, and C c2 (arg) means use val as a descriptive piece of metadata for the class.
In order to support both uses, when the type of element happens to be compatible with the descriptive argument, code that used C c2 {arg} will change meaning. There seems to be no way around it in that case if we want to support both forms with different meanings.
So what would I do? If the compiler provides some way to issue a warning, I'd make the initializer list with one argument give a warning. That sounds tricky not to mention compiler specific, so I'd make a general template for that, if it's not already in Boost, and promote its use.
Other than containers, what other situations would have initializer list and single argument constructors with different meanings where the single argument isn't something of a very distinct type from what you'd be using with the list? For non-containers, it might suffice to notice that they won't be confused because the types are different or the list will always have multiple elements. But it's good to think about that and take additional steps if they could be confused in this manner.
For a non-container being enhanced with initializer_list features, it might be sufficient to specifically avoid designing a one-argument constructor that can be mistaken. So, the one-arg constructor would be removed in the updated class, or the initializer list would require other (possibly tag) arguments first. That is, don't do that, under penalty of pie-in-face at the code review.
Even for container-like classes, a class that's not a standard library class could impose that the one-arg constructor form is no longer available. E.g. C c3 (size); would have to be written as C c3 (size, C()); or designed to take an enumeration argument also, which is handy to specify initialized to one value vs. reserved size, so you can argue it's a feature and point out code that begins with a separate call to reserve. So again, don't do that if I can reasonably avoid it.
My question is: "Can I pass the result of an assignment to a function in c++?"
The reason I want to do this is that a variable has a specific type, e.g. "int" so I assign the value to the variable and pass the whole thing to the overloaded function that takes "int" as an argument.
The main reason for doing this is to make the code a bit smaller and easier to read, so instead of:
val = 2
function(val);
I get:
function(val = 2);
Is that ok?
If so, is there a convention that says this is poor coding practice for some reason?
Thanks,
fodder
Yes
Per paragraph ยง 5.17 / 1
The assignment operator (=) and the compound assignment operators all
group right-to-left. All require a modifiable lvalue as their left
operand and return an lvalue referring to the left operand.
After function(val = 2), 2 assigns to val then the value of val passes to the function.
Talking about readability is not easy, I personally don't use this way in my codes.
"Can I pass the result of an assignment to a function in c++?"
Yes off course we can do this . compiler will break this statement function(val = 2) in
two steps that is first assign 2 to val then make a call to function with parameter 2 . therefore the first two liner approach is much cleaner and readable from the second.
C++ does indeed allow this but I wouldn't do it if I were you.
Not everything that c++ allows you to do is a good idea. A good programmer must consider two things: readability and maintainabilty. A blogger (I can't remember who) once said that a programmer doesn't program for computers, they should program for programmers.
What this means is that you should try and make things as easy to read as possible. Condensing multiple lines into one actually decreases readabilty because the reader has to stop and think about more than one thing, they have to analyse the condensed statement instead of just reading it.
What you want to do can also hide bugs created by typos. Say, for instance, you typed
function(val == 2)
by mistake. The compiler would allow this as well since it will convert a bool into an int. Another reader also won't pick up this mistake unless he/she knows the parameter list well.
If you're interested in tips and tricks and advice on good programming construction techniques, I would highly recommend Code Complete 2. I have had the book for years and I still learn new things to improve my code.
Before the shouts for duplicate begin: I am aware that the following question (and some others) are quite related to this one:
Is there a difference in C++ between copy initialization and direct initialization?
The answers in this question perfectly explains scenarios where copy initialization is not possible and explains the difference of the two and all that stuff. However, my question is more subtle:
Consider the code:
A createA(){...}
A a1 = createA();
A a2(createA());
Assume that A can be implicitly copy constructed and all that stuff, so both initializations of a1 and a2 are fine. There are no side effects in the copy constructor for A, so both initializations are also semantically equivalent. createA() returns directly the type of the variable, not something else that has to be cast first. I think this case is quite common.
So, in this case, where both alternatives are equally applicable and semantically equivalent, which one should I use? Is there a recommendation in the spec or a consensus/best practice in the community or is it just up to me and my coding style which one to use? Has C++11 introduced any difference in comparison to older standards?
If everything else is equal (semantics, performance,...) it's obviously only a matter of taste and/or style convention. However, many authors advocate a list-initializer for direct initialization these days:
A a3 {createA()};
But I'd say it's either up to you (if it's your fun project) or to your coworkers to decide on one of the two (three) alternatives. I would not recommend to use both interchangeably, because that would make readers wonder why you use sometimes direct and sometimes copy initialization.
There's no "always better" answer, it's a matter of style.
When initializing an object from a simple expression of the object's type (such as createA()) I often use copy-init, probably just due to familiarity with the = form of assignment. Otherwise, when the initializer is a different type or there are multiple initializers for the object (e.g. multiple constructor arguments, or aggregate init) I prefer to use C++11 list-initialization (a.k.a uniform initialization syntax), which can be used in more places, e.g. to initialize aggregates as well as classes with user-defined constructors, and cannot be parsed as a function declaration:
A a1{ createA() };
The above form of list-init uses direct-init, whereas this form uses copy-init:
A a2 = { createA() };
When using list-init I prefer the direct-init form without the redundant = sign.
There are a few cases where list-init isn't possible, e.g. when a type has an initializer-list constructor (i.e. one taking a parameter that is a specialization of std::initializer_list) and you want to call a different constructor, but the initializer-list constructor would get chosen, e.g. std::vector<int> v{ 5u, 0 }; will not create a vector of five elements with value zero, but a vector with two elements with values five and zero
Look at this code snippet:
Size::Size(int iSetWidth, int iSetHeight)
:iWidth(iSetWidth),
iHeight(iSetHeight)
{
}
Supposedly, this means the same thing as:
Size::Size(int iSetWidth, int iSetHeight)
{
iWidth=iSetWidth;
iHeight=iSetHeight;
}
Why would you use the former or the latter? And what is the name of the former?
No, they don't mean exactly the same.
When a constructor is executed, before entering the code block (the code between the curly braces), it constructs all object data members. What you do in the initializers (the code after the colon and before the curly braces) is to specify which constructors to use for those members. If you don't specify a constructor for a specific data member, the default constructor will be used.
So, if you use the initialization list (first example), the right constructors will be used for each member and no additional code is necessary. If you don't, first the default constructor is used and then the code inside the curly braces is executed.
In summary:
In your first example, each member is initialised using the appropriate constructor, probably the copy constructor.
In your second example, each member is constructed using the default constructor, and then some additional code is executed to initialise it, probably the assignment operator.
EDIT: Sorry, forgot to answer your questions in the last line.
The name of the code between the colon and the curly braces is initialisation list.
If you know which is the right constructor for a variable or data member, by all means use it. This is the reason why most classes have different constructors instead of just a default constructor. So you are better off using the initialization list.
The initialisation list is almost never slower than the other technique, and can easily be faster. A well known rule when writing code is "don't optimize prematurely", but there is a not so well known counterpart: don't pessimize prematurely. If you have two options for writing a piece of code and one of them can be better than the other, but does not involve additional work or complexity, use it. In your example there is no difference, since you are using a built-in type (int). But if you were using classes, there would be a difference, so get used to the initialization list.
THe former is called initilazation lists.
You can get plentyof articles for that.
The particular reasons for using intializer lists are given here
http://www.learncpp.com/cpp-tutorial/101-constructor-initialization-lists/
You can refer Effective C++ to get full insight into intializer lists.
Hope it is clear.
BTW, Bjarne Stroustrup said in The C++ Programming Language that some efficiency may be gained with initialization list and he recommended us to use initialization list!
I've started to pick up this pattern:
template<typename T>
struct DefaultInitialize
{
DefaultInitialize():m_value(T()){}
// ... conversions, assignments, etc ....
};
So that when I have classes with primitive members, I can set them to be initialized to 0 on construction:
struct Class
{
...
DefaultInitialize<double> m_double;
...
};
The reason I do this is to avoid having to remember to initialize the member in each constructor (if there are multiple constructors). I'm trying to figure out if:
This is a valid pattern?
I am using the right terminology?
This is a valid pattern?
It's a known "valid" pattern, i would say. Boost has a class template called value_initialized that does exactly that, too.
I am using the right terminology?
Well, your template can be optimized to have fewer requirements on the type parameter. As of now, your type T requires a copy constructor, unfortunately. Let's change the initializer to the following
DefaultInitialize():m_value(){}
Then, technically this kind of initialization is called value initialization, starting with C++03. It's a little bit weird, since no kind of value is provided in the first place. Well, this kind of initialization looks like default initialization, but is intended to fill things with zero, but respecting any user defined constructor and executing that instead.
To summarize, what you did was to value initialize an object having type T, then to copy that object to m_value. What my version of above does it to value initialize the member directly.
Seems like a lot of work to avoid having to type m_double(0). I think it's harder to understand at first glance, but it does seem fine as long as everything is implemented properly.
But is it worth it? Do you really want to have to #include "DefaultInitialize.h" everywhere?
To clarify, basically, you're:
Making your compile times longer because of the includes.
Your code base larger because you have to manage the deceptively simple DefaultInitialize class
Increase the time it takes other people to read your code. If you have a member of a class that's a double, that's natural to me, but when I see DefaultInitialize, I have to learn what that is and why it was created
All that because you don't like to type out a constructor. I understand that it seems very nice to not have to do this, but most worth-while classes I've ever written tend to need to have a constructor written anyway.
This is certainly only my opinion, but I think most other people will agree with it. That is: it would be handy to not have to explicitly initialize members to 0, but the alternative (your class) isn't worth it.
Not to mention that in C++0x, you can do this;
class Foo
{
private:
int i = 0; // will be initialized to 0
}
Some compilers don't properly implement value initialization. For example, see Microsoft Connect, Value-initialization in new-expression, reported by Pavel Kuznetsov.
Fernando Cacciola's boost::value_initialized (mentioned already here by litb) offers a workaround to such compiler bugs.
If you're just initializing basic types to zero, you can override new and have it memset allocated memory to zero. May be simpler. There are pros and cons to doing this.