如何使用std :: sort与对和引用

时间:2017-05-24 08:40:26

标签: c++ stl

有没有办法让排序处理对的集合,其中一个元素是一个引用? 我的代码我要对std::vector<Ty>进行排序,其中Tystd::pair<A, B&>AB为类。为了给出一个最小的具体示例,这里是typedef std::pair<int, int&> Ty的代码。这应该根据该对的第二个元素对向量进行排序。

void bad() {
  typedef std::pair<int, int &> Ty;
  int a[N] = {17, 4, 8, 10, 0};
  std::vector<Ty> v;
  for (int i = 0; i < N; ++i) {
    v.emplace_back(i, a[i]);
  }
  std::sort(v.begin(), v.end(),
            [](const Ty &a, const Ty &b) { return a.second < b.second; });

  std::cout << "With reference (bad):" << std::endl;
  for (auto &x : v) {
    std::cout << x.first << ',' << x.second << std::endl;
  }
}

输出:

With reference (bad):
4,17
3,17
2,17
1,17
0,17

但是如果我改变对指针的引用,它就像我期望的那样工作

void good() {
  typedef std::pair<int, int *> Ty;
  std::vector<Ty> v;
  int a[N] = {17, 4, 8, 10, 0};
  for (int i = 0; i < N; ++i) {
    v.emplace_back(i, &a[i]);
  }
  std::sort(v.begin(), v.end(),
            [](const Ty &a, const Ty &b) { return *a.second < *b.second; });
  std::cout << "With pointer (good):" << std::endl;
  for (auto &x : v) {
    std::cout << x.first << ',' << *x.second << std::endl;
  }
}

输出:

With pointer (good):
4,0
1,4
2,8
3,10
0,17

如果可能,我更愿意使用引用;有没有什么办法解决这一问题?我已经尝试使用调试器进行跟踪,我无法通过排序算法正确地看出为什么没有正确地复制对(可能是交换?)。

2 个答案:

答案 0 :(得分:5)

如果您使用std::reference_wrapper,那么它会按预期工作。可用Online

int N = 5;
typedef std::pair<int, std::reference_wrapper<int>> Ty;
int a[N] = {17, 4, 8, 10, 0};
std::vector<Ty> v;
for (int i = 0; i < N; ++i) {
    v.emplace_back(i, a[i]);
}

// Print, just to be sure :)
for (auto &x : v) {
    std::cout << x.first << ',' << x.second << std::endl;
}

std::sort(v.begin(), v.end(),
    [](const Ty &a, const Ty &b) { return a.second < b.second; });

std::cout << "With std::reference_wrapper (good):" << std::endl;
for (auto &x : v) {
    std::cout << x.first << ',' << x.second << std::endl;
}

答案 1 :(得分:1)

libstdc++似乎不使用swap,即使其可用性是必需的。无论如何,这似乎是合法的。可能它会做这样的事情:

typename std::iterator_traits<RandomIt>::value_type tmp = a;
a = b;
b = tmp;

第一行涉及参考初始化。 tmp.second将引用与a.second相同的内存位置。因此,最后,b.second将保留其原始值,而不是分配之前的a.second值。

为了进行比较,未使用的对交换具有更明智的行为:

swap(a.first, b.first);
swap(a.second, b.second);

请注意,即使std::sort确实使用std::pair<int, int&>::swap,语义也会与指针版本不同,因为指针版本会对指针本身进行排序,而不是对外部数组进行排序。