c++11 - Avoiding self assignment in std::shuffle -


i stumbled upon following problem when using checked implementation of glibcxx:

/usr/include/c++/4.8.2/debug/vector:159:error: attempt self move assign. objects involved in operation: sequence "this" @ 0x0x1b3f088 {   type = nst7__debug6vectoriisaiieee; } 

which have reduced minimal example:

#include <vector> #include <random> #include <algorithm>  struct type {         std::vector<int> ints; };  int main() {         std::vector<type> intvectors = {{{1}}, {{1, 2}}};         std::shuffle(intvectors.begin(), intvectors.end(), std::mt19937()); } 

tracing problem found shuffle wants std::swap element itself. type user defined , no specialization std::swap has been given it, default 1 used creates temporary , uses operator=(&&) transfer values:

  _tp __tmp = _glibcxx_move(__a);   __a = _glibcxx_move(__b);   __b = _glibcxx_move(__tmp); 

as type not explicitly give operator=(&&) default implemented "recursively" applying same operation on members.

the problem occurs on line 2 of swap code __a , __b point same object results in effect in code __a.operator=(std::move(__a)) triggers error in checked implementation of vector::operator=(&&).

my question is: who's fault this?

  • is mine, because should provide implementation swap makes "self swap" nop?
  • is std::shuffle's, because should not try swap element itself?
  • is checked implementation's, because self-move-assigment fine?
  • everything correct, checked implementation doing me favor in doing check (but how turn off)?

i have read shuffle requiring iterators valueswappable. extend self-swap (which mere runtime problem , can not enforced compile-time concept checks)?

addendum

to trigger error more directly 1 use:

#include <vector>  int main() {     std::vector<int> vectorofints;     vectorofints = std::move(vectorofints); } 

of course quite obvious (why move vector itself?). if swapping std::vectors directly error not occur because of vector class having custom implementation of swap function not use operator=(&&).

it bug in gcc's checked implementation. according the c++11 standard, swappable requirements include (emphasis mine):

17.6.3.2 §4 rvalue or lvalue t swappable if , if t swappable any rvalue or lvalue, respectively, of type t

any rvalue or lvalue includes, definition, t itself, therefore swappable swap(t,t) must legal. @ same time default swap implementation requires following

20.2.2 §2 requires: type t shall moveconstructible (table 20) , moveassignable (table 22).

therefore, swappable under definition of default swap operator self-move assignment must valid , have postcondition after self assignment t equivalent it's old value (not no-op though!) per table 22.

although object swapping not standard type, moveassignable has no precondition rv , t refer different objects, , long members moveassignable (as std::vector should be) generate move assignment operator must correct (as performs memberwise move assignment per 12.8 §29). furthermore, although note states rv has valid unspecified state, state except being equivalent it's original value incorrect self assignment, otherwise postcondition violated.


Comments

Popular posts from this blog

apache - Remove .php and add trailing slash in url using htaccess not loading css -

javascript - jQuery show full size image on click -