When following code:
std::vector<std::tuple<int&>> v;
int a = 5; v.emplace_back(a);
int b = 4; v.emplace_back(b);
int c = 3; v.emplace_back(c);
int d = 2; v.emplace_back(d);
int e = 1; v.emplace_back(e);
std::sort(std::begin(v), std::end(v));
is compiled with gcc/libstdc++ vs clang/libc++ binary gives different results.
For gcc/libstdc++ one element is copied to all the other references.
5 4 3 2 1
5 5 5 5 5
First I thought that clang/libc++ behaves as expected but it only works up to 5 elements in a vector (cause there is a special case for small containers).
5 4 3 2 1
1 2 3 4 5
When passing more elements result is similar to gcc.
5 4 3 2 1 0
3 4 5 5 5 5
So is it valid to use std::sort for container of tuples with references (i.e. made with std::tie, sorting subset of struct)?
If not, should I expect any warnings?
So is it valid to use
std::sortfor container of tuples with references (i.e. made withstd::tie, sorting subset of struct)? If not, should I expect any warnings?
No, and no. One of the type requirements on std::sort() is that:
- The type of dereferenced
RandomItmust meet the requirements ofMoveAssignableandMoveConstructible.
where MoveAssignable requires in the expression t = rv:
The value of
tis equivalent to the value ofrvbefore the assignment.
But std::tuple<int&> isn't MoveAssignable because int& isn't MoveAssignable. If you simply have:
int& ra = a;
int& rb = b;
ra = std::move(rb);
The value of ra isn't equivalent to the prior value of rb. ra still refers to a, it does not change to refer to b - what actually changed was the value of a.
Since our type doesn't meet the precondition of std::sort(), the result of the std::sort() call is just undefined behavior.
Note that you could sort a std::vector<std::tuple<std::reference_wrapper<int>>> though, because std::reference_wrapper is MoveAssignable.
Note also that this is reminiscent of not being able to sort a container of auto_ptr, per an old Herb Sutter article.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With