0
while (int grade = (std::cin >> grade, grade)) { /**/ }
  • The condition inside while declares a variable and it becomes instantly visible in the while scope
  • The second operand of assignment evaluates the expression which contains comma operator (which guarantees order of evaluation)
  • The comma's left operand yields error-status from cin and discards it, as a side effect, grade gets changed
  • Comma operator returns right hand side expression, that becomes the value of the variable

Is this legit code? I'm new to C++. Can you please correct my thought process.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 2
    It is behind the [door on the right](http://3.bp.blogspot.com/-ilMjE1Gh3Yg/VpUAmd-6TWI/AAAAAAAAAbg/-FJ08zxN42s/s1600/WFTPM.png). You do have to explain why the left door is closed. – Hans Passant Jan 13 '20 at 22:54
  • 3
    If you can't easily tell, assume it isn't. Also - really, don't write this kind of code. – einpoklum Jan 13 '20 at 22:55
  • 2
    I'm not sure why this is being closed as opinion-based. This is a question of portability/spec compliance which is quite far from an opinion question. – nanofarad Jan 13 '20 at 23:27

2 Answers2

4

It is well-defined and behaves in the expected way from C++11 up to C++17.

Before C++11, if the input operation in std::cin >> grade failed, grade would not be written to, so the right-hand grade of the comma operator would use an indeterminate value, which causes undefined behavior. Since C++11 std::cin >> grade will set grade to zero on input failure, so that this won't be a concern.

In C++20, the lifetime of grade will only begin once initialization is complete. So using it to either write to or read from in the initializer causes undefined behavior. Prior to C++20 the lifetime of a non-aggregate, non-class object began already when suitable storage for the object was obtained.


Details of the standard specification aside, you should not write code like that. Don't use a variable in its own initializer (except maybe to take a pointer/reference to it, but never to access its value). Whether or not that will work depends on many peculiarities that are not worth thinking about in order to save one additional line of code to do the declaration in a second statement.

walnut
  • 21,629
  • 4
  • 23
  • 59
  • "the lifetime of grade will only begin once initialization is complete" is true but you can vivify a trivially copyable type via assignment or is C++20 going to change that? – Ben Voigt Jan 13 '20 at 23:11
  • @BenVoigt [\[basic.life\]/7.1](https://eel.is/c++draft/basic#life-7.1) forbids *any* access to the object before the lifetime begins. So I think it wont be allowed. See also my related recent question [here](https://stackoverflow.com/questions/59442521/use-of-variable-in-own-initializer). – walnut Jan 13 '20 at 23:14
  • That means you can no longer vivify an inactive union member (of trivially copyable type) by copying from a live object? That's going to break a lot of existing code. – Ben Voigt Jan 13 '20 at 23:18
  • @BenVoigt Lifetime initiation due to assignment to union members is handled with specific rules in [\[class.union\]/6](https://eel.is/c++draft/class.union#6). – walnut Jan 13 '20 at 23:21
1

The code is legal provided that the input operation was successful. Otherwise a trap value can be used to initialize the declared variable.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335