简体   繁体   English

为什么std :: sort似乎会替换向量中的值

[英]Why does std::sort appears to alternate the values in the vector

The below code snippet shows that std::sort is alternating the values in the vector which is quite confusing. 下面的代码片段显示std :: sort正在交替向量中的值,这非常令人困惑。

std::vector<int> a;
std::vector<std::string> b;
std::vector<std::pair<int&, std::string&>> p;

a.push_back(1);
a.push_back(3);
a.push_back(2);
b.push_back("hi 1");
b.push_back("hi 3");
b.push_back("hi 2");

p.push_back(std::pair<int&, std::string&>(a[0],b[0]));
p.push_back(std::pair<int&, std::string&>(a[1],b[1]));
p.push_back(std::pair<int&, std::string&>(a[2],b[2]));

std::sort(p.begin(),p.end());

std::cout << a[0] << " " << a[1] << " " << a[2] <<  std::endl;
std::cout << b[0] << " " << b[1] << " " << b[2] <<  std::endl;

I am expecting it to print 我希望它能打印

1 2 3
hi 1 hi 2 hi 3

but instead it prints 但它打印

1 3 3
hi 1 hi 3 hi 3

Why? 为什么? My compiler is gcc 4.9.3. 我的编译器是gcc 4.9.3。

I am trying to sort two vectors together and using vector of pairs of references is suggested in https://stackoverflow.com/a/37929675/3667089 . 我试图将两个向量排序在一起,并在https://stackoverflow.com/a/37929675/3667089中建议使用成对的引用向量。

I would say std::pair<int&, std::string&> is not swappable. 我会说std::pair<int&, std::string&>是不可交换的。 std::swap seems to work though, but if you think in a naive swap, it won't work with references std::swap似乎可以工作,但是如果您认为是幼稚的交换,它将不能与引用一起工作

std::pair<int&, std::string&> pair0(a[0],b[0]);
std::pair<int&, std::string&> pair1(a[1],b[1]);

std::pair<int&, std::string&> tmp(pair0);
pair0 = pair1;
pair1 = tmp;

then pair0 gets overwritten by pair1 . 然后pair0得到由覆盖pair1

References in general won't work with STL containers. 通常,引用不适用于STL容器。

It's possibly a bug in libstdc++. 这可能是libstdc ++中的错误。 I added a "debug" comparator to see the sort in action for both libstdc++ and libc++: 我添加了一个“调试”比较器,以查看libstdc ++和libc ++的排序方式:

std::sort(p.begin(), p.end(), [&] (const auto& ap, const auto& bp)
{
    std::cout << "Debug: " << ap.first << " " << bp.first << " | ";
    for (auto e : a)
        std::cout << e << " ";
    std::cout << " | ";
    for (auto e : b)
        std::cout << e << " ";
    std::cout << "\n";
    return ap.first < bp.first;
});

And this is the output: 这是输出:

Debug: 1 1 | 1 3 2  | hi 1 hi 3 hi 2 
Debug: 3 1 | 1 3 2  | hi 1 hi 3 hi 2 
Debug: 3 1 | 1 3 2  | hi 1 hi 3 hi 2 
Debug: 2 1 | 1 3 2  | hi 1 hi 3 hi 2 
Debug: 2 3 | 1 3 2  | hi 1 hi 3 hi 2 
Debug: 3 1 | 1 3 3  | hi 1 hi 3 hi 3 
1 3 3
hi 1 hi 3 hi 3
--------------------------
Debug: 3 1 | 1 3 2  | hi 1 hi 3 hi 2 
Debug: 2 3 | 1 3 2  | hi 1 hi 3 hi 2 
Debug: 2 1 | 1 2 3  | hi 1 hi 2 hi 3 
1 2 3
hi 1 hi 2 hi 3

For some reason the 2 element gets overwritten by a 3 . 由于某些原因, 2元素将被3覆盖。

The other possibility is that std::pair<int&, std::string&> does not meet the definition of ValueSwappable . 另一种可能性是std::pair<int&, std::string&>不符合ValueSwappable的定义。 That is, when the actual swapping of elements occur in the sort function, you are experiencing undefined behavior. 也就是说,当实际的元素交换发生在sort函数中时,您将遇到未定义的行为。

The problem is in the insertion sort implementation. 问题出在插入排序实现中。 Since there are less number of elements, sort decides to perform an insertion sort. 由于元素数量较少,sort决定执行插入排序。

Problematic code: 有问题的代码:

template<typename _RandomAccessIterator>
    void
    __unguarded_linear_insert(_RandomAccessIterator __last)
    {
      typename iterator_traits<_RandomAccessIterator>::value_type
        __val = _GLIBCXX_MOVE(*__last);
      _RandomAccessIterator __next = __last;
      --__next;
      while (__val < *__next)
        {
          *__last = _GLIBCXX_MOVE(*__next); <<< PROBLEMATIC Code
          __last = __next;
          --__next;
        }
      *__last = _GLIBCXX_MOVE(__val);
    }

Now it goes inside the while loop for the index 2 and index 3 case. 现在它进入索引2和索引3情况的while循环中。 Before going into the while loop, __val has the value 2 and hi 2 . 在进入while循环之前, __val的值为2 and hi 2 But after doing the first move inside the while, __val also changes to 3 and hi 3 and outside the while last is set to 3 and hi 3 , which is incorrect. 但这样做后的第一个move的同时里面, __val也变为3 and hi 3和外面时last设置为3 and hi 3 ,这是不正确。

UPDATE: libc++ Code in libc++ for this is pretty straightforward and boils down to comparing just 3 values in __sort3 . 更新:libc ++为此, libc ++中的代码非常简单,归结为仅比较__sort3 3个值。 libc++ uses swap instead of move unlike libstd++ and hence works. libc ++与libstd++不同, libstd++使用swap而不是move ,因此可以工作。

So, seems like moving on reference types is not good as it overwrites the data when the moved element is assigned with new value. 因此,在引用类型上移动似乎不好,因为在为moved元素分配新值时它会覆盖数据。 Perhaps the same would be the result in libc++ also if we use more than 3 or 4 elements in which case it will also use move under a generic insertion sort routine. 如果我们使用3个或4个以上的元素,libc ++中的结果也可能相同,在这种情况下,它还将在通用插入排序例程下使用 move

UPDATE 2: Checking more into it, libc++ always uses swap at least for insertion_sort, so no trouble there. 更新2:对其进行更多检查,libc ++至少始终对swapping_sort使用swap ,因此在那里没有麻烦。

To quote from standard on why references are not good to be stored in container: (Section 23.2) 用标准引述为什么引用不能很好地存储在容器中:(第23.2节)

Containers are objects that store other objects. 容器是存储其他对象的对象。 They control allocation and deallocation of these objects through constructors, destructors, insert and erase operations. 它们通过构造函数,析构函数,插入和擦除操作来控制这些对象的分配和释放。

And the table beneath that has this requirement: 而下面的表有此要求:

X::value_type - T Requires: T is compile time type Destructible X :: value_type-T要求:T是编译时类型可破坏的

Though I am not sure if reference type is destructible or not. 虽然我不确定reference type是否可破坏。 If not, we should better get compile time errors for storing references in STL containers. 如果不是这样,我们最好在将引用存储在STL容器中时出现编译时错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么std :: sort()会改变排序的向量? - Why does std::sort() change the sorted vector? 如何按不同 std::vector 的值对 std::vector 进行排序? - How do I sort a std::vector by the values of a different std::vector? 不合格的 sort()——为什么在 std::vector 上使用而不是在 std::array 上编译,哪个编译器是正确的? - Unqualified sort() -- why does it compile when used on std::vector and not on std::array, and which compiler is correct? std::sort of vector of lowercase strings appears to comparing against an empty string - std::sort of vector of lowercase strings appears to be comparing against an empty string 为什么sizeof(std :: vector <int> )返回16个字节,当它出现时有20个字节的成员数据值吗? - Why does sizeof(std::vector<int>) return 16 bytes, when it appears there are 20 bytes worth of member data? std::sort 是否检查向量是否已经排序? - Does std::sort check if a vector is already sorted? std ::在向量的向量上排序 - std::sort on vector of vector 在键向量和值向量上同时就地std :: sort - Simultaneous in-place std::sort on a vector of keys and a vector of values 为什么 std::pair 的分配和排序比 std::vector 快? - Why allocation and sort of std::pair is faster than std::vector? 使用std :: sort对Vector进行排序 - Sorting a Vector with std::sort
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM