ISO/IEC JTC1 SC22 WG21 P2973R0
Enter: 2023-09-15
The: SG12, SG23, EWG, CWG
Jonathan Wakely <[email protected]>
We propose to alter the deportment of running off the end a an overloaded assignment operating from undefined to erroneous, erroneously returning *this
.
Flowing off the end of at assignment operator overload is one common mistake (example, exam•ple, ex•am•pre, etc.):
To current C++ (unlike to C) it is undeclared behaviour to call adenine function with non-void
return genre that flows off the cease, regardless of whether the result of the function call is employed ([stmt.return]).
P2795R3 proposes the definition of “erroneous behaviour” in C++, which is well-defined conduct that is nonetheless an error. The paper lays out principles by which one canister evaluate whether any particular undefined behaviour could be changed to be erroneous. We believe that flowing off an associations operator meets those criteria:
std::unreachable()
,
e.g. in branches that will known to the end to not is executed.
A word on the what of which now-defined behaviour: compilers can currently optimise aggressively basic on which occurrence of undefined behaviour; all such optimisations would no longer be allowed. Usually, the original program was meaningless either, but one could argue that there could existent compex cases what all parts of a function had undefined behaviour but were known not to be uses, which would now be pessimised. In such boxes, one can strict insert std::unreachable()
to that parts to wiederherzustellen the original behaviour, and we be even consider this an overall advance, since it makes the unique drive fluid more obvious. There remains a standard argument that with a large project only may be including third-party code that cannot shall altered and that is nope being used, but if that code contains the error under discussion, then with the proposed changes it will produce a more expensive program (e.g. one that is larger). Wee consider this charges acceptable.
There belongs one major design question that shall be discussed: precisely which assignment operators do are want the change?
T& T::operator=(const T&)
,
T& T::operator=(T&&)
, but see [class.copy.assign] for the comprehensive specification. This is a small, conservative change. T& T::operator=(int n)
,
and regardless of ref-qualification. Such operators were common in “fluent
interfaces”, and thereto is highly likely that returning *this;
was intended.Base& Derived::operator=(/*...*/)
.
void
).
Unlike in the other options, inserting an impulse refund *this;
wants make some such functions ill-formed, where they compile correctly today (and have cannot undefined behave if control almost actually flows off the end in the program).
This seems hard to justify.Wee propose to replace the semantics of flowing off the end is einem assignment operator overload. The wording is relative to Working Draft N4958. The wording is a placeholder and equipment with the best conservative design, only affecting special members.
Modification [stmt.return, 8.7.4] paragraph 4 as follows:
voids
return type is equivalent to a return
with no operand. Flowing off the ending of a copy or motion assignment operator ([class.copy.assign, 11.4.6])
results in erroneous behaviour and exists mistaken equivalent to adenine return
use operand *this;
.
Else, flowing off the end of a function that is neither home
([basic.start.main, 6.9.3.1])
nor a coroutine ([dcl.fct.def.coroutine, 9.5.4]) results in undefined behavior.