[multi_array] std::swap and subarray
Hello!
I've got somehow unexpected behaviour of std::swap with multi_array's
subarray. For example, given a 2x2 multi_array:
boost::multi_array
Hi Sergey, Ultimately, the problem is the compiler I think.
I've got somehow unexpected behaviour of std::swap with multi_array's subarray. For example, given a 2x2 multi_array: ... std::swap( a[0], a[1] );
With msvc 2008 + boost 1.42, one of the rows overwrites the other and the output is:
21 22 21 22
The problem is that a[0] and a[1] are temporary objects, and they cannot be swapped in the std::swap sense (since it takes two reference to non-const). fortunately gcc 4 catches this problem and your original code doesn't compile. Then using your hack doesn't work either (i.e. doesn't compile in gcc 4)
template
void swap( boost::detail::multi_array::sub_array &lhs, boost::detail::multi_array::sub_array &rhs)
...because of the same reason.
Well, probably that's not a problem for now, but I dunno if it's a bug or std::swap is not supported - coundn't find anything about this.
it is a (conceptual) bug in your compiler that allows you to take a
temporary as a non-const reference. (gcc wins for the conceptual
superiority this time).
Now, to solve your problem with the smallest change possible you can
try with
template
I think this solves the problem, (except for the fact that there it may be a more efficient way by swapping element by element).
complete code:
--
#include
Hello alfC, Thanks for explanation! Yes, the code you provided works perfectly with my compiler :). The actual problem I've faced is that std::random_shuffle makes a mess with multi_array in msvc 2008. The interesting fact is that std::iter_swap, which is used by std::random_shuffle, works in gcc without one more overload in std: //std::swap( a[0], a[1] ); std::iter_swap( a.begin(), a.begin()+1 ); Looks like msvc's std::iter_swap always uses std::swap, while gcc's one uses it only when iterator_traits<...>::reference is the same as value_type&. Ok, now I see I don't really understand how stl handles types with reference semantics. Looks like std::swap should be overloaded. Maybe stl algorithms shouldn't be used with such types at all? Cheers, Sergey Mitsyn. On 20.02.2010 8:26, alfC wrote:
Hi Sergey,
Ultimately, the problem is the compiler I think.
I've got somehow unexpected behaviour of std::swap with multi_array's subarray. For example, given a 2x2 multi_array: ... std::swap( a[0], a[1] );
With msvc 2008 + boost 1.42, one of the rows overwrites the other and the output is:
21 22 21 22
The problem is that a[0] and a[1] are temporary objects, and they cannot be swapped in the std::swap sense (since it takes two reference to non-const). fortunately gcc 4 catches this problem and your original code doesn't compile.
Then using your hack doesn't work either (i.e. doesn't compile in gcc 4)
template
void swap( boost::detail::multi_array::sub_array &lhs, boost::detail::multi_array::sub_array &rhs) ...because of the same reason.
Well, probably that's not a problem for now, but I dunno if it's a bug or std::swap is not supported - coundn't find anything about this.
it is a (conceptual) bug in your compiler that allows you to take a temporary as a non-const reference. (gcc wins for the conceptual superiority this time).
Now, to solve your problem with the smallest change possible you can try with
template
void swap( boost::detail::multi_array::sub_array lhs, boost::detail::multi_array::sub_array rhs) { ... same code here } note two changes, 1) we must use boost::detail::multi_array::size_type instead of int, otherwise the overload template is not found in cases where the size_t is not int for example). 2) use plain variable type as argument, you may say: What a waste to pass by value!! well is not that bad because sub_arrays are really references already, elements are not copied.
It works in gcc (actually this is the only variant that compiles with gcc), Let me know your results in VS2008.
I think this solves the problem, (except for the fact that there it may be a more efficient way by swapping element by element).
Good luck, Alfredo
Ok, now I see I don't really understand how stl handles types with reference semantics. Looks like std::swap should be overloaded. Maybe stl algorithms shouldn't be used with such types at all?
I also felt hesitant of overloading std::swap by value, instead as the generic template that uses references... On one hand, std::swap is meant to be overloaded in certain circumstances, but changing the input type? I don't know. on the other hand: it works, and it does what is supposed to do for sub_arrays, and it also seems to work in more generic circumstances (under std::random_shuffle), so what? If it works it is the right thing. In any case I would be more worried about defining the overload of std::swap with the right implementation by swapping element by element, instead of creating a huge temporary array. If you figure out that code, please paste it here. By the way, now that I am thinking about it, the std::swap of subarray that we defined should work recursively so we can use the std::swap inside our std::swap for each subsubarray of the subarray. If it is an element (not another subsubarray) still will do the right thing. ah! generic code is so beautiful! That leads me to think that we are doing something that not only works but also that we are doing it in right way. Alfredo
In any case I would be more worried about defining the overload of std::swap with the right implementation by swapping element by element, instead of creating a huge temporary array. If you figure out that code, please paste it here.
I couldn't resist, here is the code that properly swaps subarrays, it
should work for subarrays of arbitrary dimension and creates no big
temporaries (just element temporaries).
--
#include
participants (2)
-
alfC
-
Sergey Mitsyn