c++ - Is std::swap(x, x) guaranteed to leave x unchanged? -
this question based on discussion below recent blog post scott meyers.
it seems "obvious" std::swap(x, x)
should leave x
unchanged in both c++98 , c++11, can't find guarantee effect in either standard. c++98 defines std::swap
in terms of copy construction , copy assignment, while c++11 defines in terms of move construction , move assignment, , seems relevant, because in c++11 (and c++14), 17.6.4.9 says move-assignment need not self-assignment-safe:
if function argument binds rvalue reference parameter, implementation may assume parameter unique reference argument. ... [ note: if program casts lvalue xvalue while passing lvalue library function (e.g. calling function argument move(x)), program asking function treat lvalue temporary. implementation free optimize away aliasing checks might needed if argument lvalue. —end note ]
the defect report gave rise wording makes consequence clear:
this clarifies move assignment operators need not perform traditional if (this != &rhs) test commonly found (and needed) in copy assignment operators.
but in c++11 , c++14, std::swap
expected use implementation,
template<typename t> void swap(t& lhs, t& rhs) { auto temp(std::move(lhs)); lhs = std::move(rhs); rhs = std::move(temp); }
and first assignment performing assignment self argument rvalue. if move assignment operator t
follows policy of standard library , doesn't worry assignment self, seem court undefined behavior, , mean std::swap(x, x)
have ub, well.
that's worrisome in isolation, if assume std::swap(x, x)
supposed safe in c++98, means c++11/14's std::swap
silently break c++98 code.
so std::swap(x, x)
guaranteed leave x
unchanged? in c++98? in c++11? if is, how interact 17.6.4.9's permission move-assignment not self-assignment-safe?
your assumption c++11/14 std::swap
implementation wrong. in version temp
being copy constructed 1 of arguments; however, there's no need this. temp
can move constructed, , rest remains same example
template<typename t> void swap(t& lhs, t& rhs) // omitting noexcept specification { t temp = std::move(lhs); lhs = std::move(rhs); rhs = std::move(temp); }
the second statement still self-move-assignment, resource owned lhs
(and rhs
) has been moved temp
. both objects should in "valid unspecified" state, , assignment shouldn't cause trouble @ point.
edit: found this answer howard hinnant discusses situation (about 2/3rds of way down). assessment same above.
Comments
Post a Comment