有没有办法让排序处理对的集合,其中一个元素是一个引用?
我的代码我要对std::vector<Ty>
进行排序,其中Ty
为std::pair<A, B&>
,A
和B
为类。为了给出一个最小的具体示例,这里是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
如果可能,我更愿意使用引用;有没有什么办法解决这一问题?我已经尝试使用调试器进行跟踪,我无法通过排序算法正确地看出为什么没有正确地复制对(可能是交换?)。
答案 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
,语义也会与指针版本不同,因为指针版本会对指针本身进行排序,而不是对外部数组进行排序。