13

I've seen a lot of code in textbooks and in the forums that people use the assignment operator over the initialisation one in a for loop to start the repetition. For example,

for ( int i = 0; i < 5; ++i )   // common 
for ( int i(0);  i < 5; ++i ) // uncommon 

I know that initialising a variable is faster than assigning it. Why do people prefer the former over the later?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
CroCo
  • 5,531
  • 9
  • 56
  • 88
  • 24
    _"I know that initialing a variable is faster than assigning it. "_ Uhm what? Both of the forms are variable initializations, 1st is not assignment. – πάντα ῥεῖ Jan 02 '15 at 16:47
  • The second one is not so intuitive for mathematicians... – nbro Jan 02 '15 at 16:49
  • 8
    That's not the assignment operator. :) `int i = 0` is initialization (despite using `=`), whereas `i = 0` would be assignment. When you declare the variable on the same line, it is initialization, not assignment. – jalf Jan 02 '15 at 16:53
  • 13
    Coming soon to a theater near you: `for ( int i{0}; i < 5; ++i )` – Michael Gazonda Jan 02 '15 at 16:55
  • So if I have a picture whose size is 1M, which one is better to use? `image1 = image 2` or `image1(image2)`? I'm getting confused. – CroCo Jan 02 '15 at 16:55
  • 3
    @CroCo that question is unanswerable from information you get here. It's going to depend on how your images are implemented. – Michael Gazonda Jan 02 '15 at 16:56
  • 6
    @CroCo You are confusing two things. You seem to think that `T u = v;` is the same as `u = v;` (or `T u; u=v;`), while they are not. The very base premise of your question is wrong then, because both versions of what you wrote are the same, as explained. – luk32 Jan 02 '15 at 16:57
  • 5
    @CroCo Also please note that such a construct as `image1(image2)` can have different meanings depending on context. This can be a function call, or a constructor. Yours examples look like a function call and assignment operator. Whereas if you put type before (`T image(image2);` or `T image = image2;`), they would both become copy constructors (given that both images are of the same type `T` of course). – luk32 Jan 02 '15 at 17:04
  • According to the consensus on meta, the correct resolution for a question that assumes incorrect facts is to close it as a duplicate of a question&answer which explain the reality. http://meta.stackoverflow.com/q/258731/103167 – Ben Voigt Jan 02 '15 at 19:01

4 Answers4

28

Both int i = 0; and int i(0); declare, define and initialize an int object with the value 0 in C++. They are strictly equivalent, so are the two loop constructs. Note that in C, int i(0); is not an allowed construct.

ouah
  • 142,963
  • 15
  • 272
  • 331
  • Is the second case a C++11 (and later versions) feature? – nbro Jan 02 '15 at 16:50
  • `Why people prefer the former over the later?` ? – Shahriar Jan 02 '15 at 16:51
  • @Rinzler No, only the (also equivalent) `int i {0}` and `int i{}` would be. – Baum mit Augen Jan 02 '15 at 16:53
  • 1
    @Rinzler: No, C++ has had direct initialisation since the dawn of time. Since C++11, `int i{0};` is an alternative. – Mike Seymour Jan 02 '15 at 16:53
  • @MikeSeymour Why new alternatives? Are they useful? – nbro Jan 02 '15 at 16:54
  • 4
    @AerofoilKite: Not all people do. Those who learnt C before C++ might prefer the former for its familiarity. – Mike Seymour Jan 02 '15 at 16:54
  • 1
    @Rizler it's OK since the first version c++98 of the language. – ouah Jan 02 '15 at 16:54
  • 3
    @Rinzler They have no advantage in this case. Sometimes they are better. See [here](http://herbsutter.com/2013/05/09/gotw-1-solution/) for more details. – Baum mit Augen Jan 02 '15 at 16:56
  • 2
    @AerofoilKite maybe the first version is more idiomatic as it is closer to the C89 for loop `for (i = 0; i < 5; ++i)`. – ouah Jan 02 '15 at 16:57
  • 3
    @Rinzler: For simple types like this, brace-initialisation is equivalent to the other styles, and there's no particular reason to prefer any of them. It has various uses, including avoiding the "most vexing parse" (e.g. `int i();` doesn't declare a variable, but `int i{};` does), and for classes like `std::vector` to allow initialisation from a list of elements. – Mike Seymour Jan 02 '15 at 16:58
  • 2
    @MikeSeymour: `int i();` is _not_ the "most vexing parse". – Lightness Races in Orbit Jan 02 '15 at 17:20
  • 2
    @LightnessRacesinOrbit: That rather depends on how vexing you happen to find the various parsing quirks. There's no "official" meaning of the term; I use it to mean any unexpected interpretation of a language construct, regardless of what Meyers might have been specifically talking about when he coined the term. – Mike Seymour Jan 02 '15 at 18:04
  • 2
    @MikeSeymour: So you consider C++03's `foo<3 > 2>` to be an example of the most vexing parse? – Lightness Races in Orbit Jan 02 '15 at 18:07
  • 1
    @LightnessRacesinOrbit: I consider it to be a vexing parse, yes. Whether or not it's the most vexing depends on how much you happen to be vexed by it. Unless you insist that the informal phrase only be used for whatever you happen to think it should mean, of course; in which case, it probably isn't. – Mike Seymour Jan 02 '15 at 18:11
  • 1
    They are not "strictly equivalent". Pedantically, one is copy initialization and one is direct initialization. Both initialization forms have the same behavior for primitive types, but in general they are not the same. – Ben Voigt Jan 02 '15 at 18:56
9

Two forms of initialization you mentioned are:-

T t = u;     _1
T t(u);      _2

_1

This could involve two calls. One would be to conversion constructor and another would be to copy constructor.Although most compiler can elide the copy construction.

_2

This would just require only a single call to conversion constructor.

So, _2 is preferred over _1. As for built-in types, it won't make much difference.

ravi
  • 10,994
  • 1
  • 18
  • 36
  • 1
    In practice, especially when `u` is a `T`, those copies will be entirely elided. – Lightness Races in Orbit Jan 02 '15 at 17:20
  • 2
    Why is this answer upvoted ? If there is a constructor which support `T t(u);` , in that particular case `T t=u;` won't involve 2 calls. It will call either a constructor or copy constructor. If otherwise, kindly post a sample and I will reverse the vote. I just tried with gcc – kiranpradeep Jan 02 '15 at 17:45
  • class Base { private: int data; public: Base(int x) : data(x) { cout << "Conversion constructor" << endl; } Base(const Base& b) : data(b.data) { cout << "Copy constructor" << endl; } }; int main() { Base b = 2; Base b(2); } – ravi Jan 02 '15 at 17:51
  • @Kiran Also, please note comment by "Lightness Races in Orbit". Call to copy constructor can be elided by some compiler. That's why I said preferred not mandatory. – ravi Jan 02 '15 at 17:52
  • I tried gcc with your sample and it didn't invoke copy constructor. Which compiler will invoke "copy constructor" ? – kiranpradeep Jan 02 '15 at 17:56
  • 1
    If there is no compiler, then this kind of an answer should be supported by reference to standard. Also kindly note that the reference to "built in types won't make much difference" is not helpful and could be confusing to OP. If the statement _1 was true, then that would have called two constructor like invocations for built in types, and that itself would have made a difference however minor. – kiranpradeep Jan 02 '15 at 18:05
  • 4
    @Kiran: Any compiler might invoke the copy constructor for `_1` if you disable copy elision. It might not if it chooses to elide the copy, since this is one situation (initialising an object from a temporary of the same type) where that optimisation is permitted. Direct initialisation, in `_2`, won't invoke the copy constructor. The answer is correct for class types; and, as it says, there's little difference for trivial types. – Mike Seymour Jan 02 '15 at 18:18
  • 4
    If the copy constructor is private g++ 4.8.3 doesn't compile the first example, but the second one. (this seems like the correct behavior but I haven't read the standard - VS2013 compiles both cases). I'd say that's the rather more important difference than a slight possible performance difference. – Voo Jan 02 '15 at 18:19
  • @Voo. Yes. That is correct. and I have reversed the vote. Still believe this answer doesn't helps OP. – kiranpradeep Jan 02 '15 at 18:22
  • 1
    @MikeSeymour. Thanks. Didn't knew about copy elision and just tried with `-fno-elide-constructors` flag which invoked both constructors. – kiranpradeep Jan 02 '15 at 18:41
  • It's probably also worth mentioning that the type of conversion constructor is different - in 1 it's an _implicit_ conversion, whereas in 2 is an _explicit_ conversion. Not relevant for ints, but may be relevant for some derived types. – R.M. Jan 02 '15 at 23:03
  • 1
    @R.M. Please define "explicit conversion". – curiousguy Jan 03 '15 at 02:16
  • @curiousguy Explicit is the opposite of implicit. See e.g. http://stackoverflow.com/questions/7099957/implicit-vs-explicit-conversion http://stackoverflow.com/questions/121162/what-does-the-explicit-keyword-in-c-mean and linked. Post-Cxx11, the ["explicit" specifier](http://en.cppreference.com/w/cpp/language/explicit) can be applied to constructors to say they should not be used for [implicit conversions](http://en.cppreference.com/w/cpp/language/implicit_cast). If the relevant conversion constructor is marked as explicit, form 2 here will work but form 1 will give a compiler error. – R.M. Jan 05 '15 at 23:32
  • @R.M. "_Post-Cxx11, the "explicit" specifier can be applied to constructors to say they should not be used for implicit conversions._" I get that. It isn't just "post" anything, it existed in the very first standard approved in 1997. – curiousguy Jan 06 '15 at 10:26
  • @curiousguy Sorry, you're right. The important use cases I was thinking of (shared pointers) become important post-Cxx11, but "explicit" itself predates that. – R.M. Jan 06 '15 at 15:41
1

You can write is as well as:

int i(5);

or

int i{5};

or

int i=5;

All of these are initializations-not assignments. *And they're not different.

I I
  • 180
  • 1
  • 7
0

In C programming language, you have to define the variables first and initialize them afterwards. To perform a for cycle, you would need to define the variable in the beginning of the function, and only then write for( i=0 ; i<5 ; ++i ). So, people who often use this language, might not be used to this type of assignment, possible in C++, or just don't want to confuse possible beginner readers.

However, in C++, using for( int i=0 ; i<5 ; ++i ) and for ( int i(0); i < 5; ++i ) is the same, since in both cases the variables are created before the first iteration of the cycle.

bandrade
  • 143
  • 1
  • 6
  • Well... if you write `int i; for(i=0 ; i<5 ; ++i );` it will also be created before the 1st loop, but it is different. The reason the two mentioned versions are the same is different. It is so because the standard says that `int i = 0;` and `int i(0);` are equivalent invocations of the copy constructor. – luk32 Jan 02 '15 at 17:07
  • This is all correct, strictly, but your application of it to the question is not quite right. The two constructs are the same because they are the same, not because they are created before the first iteration of the _loop_. – Lightness Races in Orbit Jan 02 '15 at 17:22
  • 3
    "To perform a for cycle, you would need to define the variable in the beginning of the function, and only then write `for( i=0 ; i<5 ; ++i )`" -- that's just patently false, unless you are a time traveler from the last millennium. C99 allows `for( int i=0 ; i<5 ; ++i )`, and this is *far* more idiomatic to any C programmer. –  Jan 02 '15 at 19:51