std::set 和 < 运算符重载的奇怪行为?
Strange Behavior of std::set and < Operator Overloading?
我知道,如果<
运算符在C++中重载(例如,将自定义结构插入std::set
),则实现必须是对底层类型的严格弱顺序。
请考虑以下struct
和实现。 这个实现不是一个严格的弱顺序,但代码编译和运行时不会抛出错误(鉴于严格的弱顺序的要求,我希望它会抛出错误):
#include <iostream>
#include <set>
using namespace std;
struct Pixel {
int x;
int y;
};
bool operator < (Pixel lhs, Pixel rhs){
return lhs.x < rhs.x || lhs.y < rhs.y;
};
int main(){
set<Pixel> mySet;
Pixel *newPixelA = new Pixel;
newPixelA->x = 1;
newPixelA->y = 3;
Pixel *newPixelB = new Pixel;
newPixelB->x = 4;
newPixelB->y = 2;
mySet.insert(*newPixelA);
mySet.insert(*newPixelB);
}
这是预期的行为吗? 编辑:使用Xcode。
编译器
无法确定您的operator<
是否为严格的弱排序。相反,std::set
要求这样做的意思是,只有给它一个严格的弱排序,它才能正常工作。它不保证如果你给它别的东西会发生什么。
一般来说,当C++需要某事时,这意味着你有责任确保某事发生。如果这样做,那么编译器和库将保证您获得正确的结果。
如果满足比较器要求,标准保证预期行为。否则,会发生什么取决于实现和数据集。您的比较函数可能适用于某些数据集(对于所有点,较大的 x 意味着更大的 y)。Set 不能包含相等元素(作为数学概念),对于std::set
等价意味着相等,所以如果已经有值b
,它只会阻止你插入值a
,例如:
a < b == true
b < a == true
即使a
可能不等于b
当比较运算符对所包含元素实现严格的弱排序时,std::set
中的对象按可预测的模式排序。否则,当您迭代对象时,无法知道哪个对象首先出现在std::set
中。
采用以下示例程序,其中Pixel1
的排序不正确,Pixel2
的排序正确。
#include <iostream>
#include <set>
struct Pixel1 {
int x;
int y;
};
bool operator < (Pixel1 lhs, Pixel1 rhs){
return lhs.x < rhs.x || lhs.y < rhs.y;
};
struct Pixel2 {
int x;
int y;
};
bool operator < (Pixel2 lhs, Pixel2 rhs){
if ( lhs.x != rhs.x )
{
return (lhs.x < rhs.x);
}
return (lhs.y < rhs.y);
};
template <typename Pixel> void print(std::set<Pixel> const& mySet)
{
for ( Pixel p : mySet )
{
std::cout << "(" << p.x << ", " << p.y << ") ";
}
std::cout << std::endl;
}
template <typename Pixel> void test1()
{
std::set<Pixel> mySet;
Pixel pixelA = {2, 3};
Pixel pixelB = {4, 2};
Pixel pixelC = {4, 1};
mySet.insert(pixelA);
mySet.insert(pixelB);
mySet.insert(pixelC);
print(mySet);
}
template <typename Pixel> void test2()
{
std::set<Pixel> mySet;
Pixel pixelA = {2, 3};
Pixel pixelB = {4, 2};
Pixel pixelC = {4, 1};
mySet.insert(pixelB);
mySet.insert(pixelA);
mySet.insert(pixelC);
print(mySet);
}
int main()
{
std::cout << "Pixel1 ... n";
test1<Pixel1>();
test2<Pixel1>();
std::cout << "Pixel2 ... n";
test1<Pixel2>();
test2<Pixel2>();
}
输出
Pixel1 ...
(4, 1) (4, 2) (2, 3)
(4, 1) (2, 3) (4, 2)
Pixel2 ...
(2, 3) (4, 1) (4, 2)
(2, 3) (4, 1) (4, 2)
std::set<Pixel1>
中对象的顺序取决于插入顺序,而std::set<Pixel2>
中对象的顺序与插入顺序无关。
只有您才能知道这在您的应用程序中是否可以接受,
相关文章:
- 为什么Mat类的两个对象可以在不重载运算符+的情况下添加
- 重载运算符new[]的行为取决于析构函数
- 为什么将值返回函数传递给重载=运算符对运算符函数有效,而对其他运算符无效
- 在 myVector 类中重载运算符 + 时出错
- 为什么常量词在重载运算符中不与 ostream 对象一起使用<<?
- 如何在 cpp 中重载运算符 +=?
- C++ 如何重载 [] 运算符并进行函数调用
- 重载运算符的范围是什么?它是否会影响作为类成员的集合的插入函数?
- 为什么我可以在不重载 "=" 运算符的情况下将一个对象分配给另一个对象?
- 重载运算符有地址吗?
- 如何迭代重载运算符 [] 的类?
- 重载运算符与添加问题
- 模板基类中的重载运算符
- 如何调用用于重载运算符"<<"的 friend 函数?
- 在 C++17 中的命名空间和子命名空间中重载运算符是不明确的
- 重载运算符<<采用谷歌 C++ 风格
- C++ 如何正确重载 + 运算符
- cout (<<) 重载运算符不打印减去的矩阵
- 如何在 c++ 中重载运算符 + 以便能够 whrite c_str = "smth" + c_str;
- 重载运算符*以获取对另一个类的实例的引用