Does it improve safety to mark assignment operator

2019-01-19 13:05发布

If T is a class type with the default signature for assignment operator, then we can write:

T const &ref = ( T{} = something ); 

which creates a dangling reference. However, with the signature:

T &operator=(T t) &

the above code with dangling reference will fail to compile. This would prevent some situations where we return an lvalue that designates a temporary object -- undesirable situations because they can lead to dangling references.

Is there any reason not to do this; would we be disabling any valid use cases for the assignment operators?

I think the same comments can apply to the compound assignment operators too, += etc. A more realistic case might be:

std::string const &s = std::string("Hello, ") += "world!";

where the typo would go unnoticed until runtime UB.

1条回答
甜甜的少女心
2楼-- · 2019-01-19 13:49

In my experience in the rare case you do want to assign to an rvalue, writing

template<class T>
std::remove_reference_t<T>& as_lvalue(T&&t){return t;}

and doing as_lvalue( tmp() ) = foo instead of tmp()=foo is not a huge barrier. It does mean that the occasional bit of code that did assign to an rvalue is now going to break; I personally would suspect most such cases are actually uncaught bugs.


Restricting every type in std to be lvalue-restricted on operator= was considered during C++11 standardization in Frankfurt (2009/07). The resolution reasoning recorded in the minutes was:

N2819, "N2819 Ref-Qualifiers for assignment operators of the Standard Library" was initially considered by the LWG. This proposal sought to change 350 copy-assignment operators in the C++ standard library to prevent assignment operations in which the left operand is an rvalue. Due to the large number of changes required, the proposal was sent to EWG, with the request that the default behavior for implicit copy-assignment operators be reconsidered, so that assignment to an rvalue is not permitted. The EWG resolved to maintain the status quo, because of concerns about backwards compatibility.

I read that as saying "350 changes? How about a language change?". EWG said "no, that language change could break compatibility". And possibly the proposal died on the vine.

In 2009, C++11 (then C++0x) was already behind schedule. As the proposition involved 300 changes to the library that (in theory) could cause regressions. No other reason was cited in the minutes. It being declined for not being worth the pain of regressions (or even checking for the frequency of regressions!) is understandable. So I wouldn't presume prejudice on the idea just because C++ rejected it in std.

查看更多
登录 后发表回答