我正在使用一个向量,其类类型为A
作为其元素类型。我为我的类定义了关系运算符<
,但是当我比较其中两个向量时,它就会崩溃。
class A {
public:
explicit A(int){}
bool operator<(const A&)const {
return true; // for simplicity
}
};
int main() {
std::vector<A> v{ A(1), A(2), A(3), A(4), A(5) };
std::vector<A> v2{ A(0), A(2), A(4), A(6) };
std::cout << (v < v2) << std::endl; // program crashes here!
}
我试图理解这一点,因为我已经读到STL容器使用元素类型的关系运算符?!
程序在GCC上运行良好,但在MSVC ++ 14上崩溃,因此我收到断言对话框,抱怨行std::cout << (v < v2) << std::endl; // program crashes here!
@ user4581301指出的最有趣的事情是,如果我正确定义关系运算符,它将解决此问题:
class A {
public:
explicit A(int) {}
bool operator<(const A& a)const {
return x < a.x; // for simplicity
}
int x;
};
现在,它可以正常运行,并且程序不会崩溃! MSVC ++中有一些限制吗? (我的意思是正确定义运算符?)
答案 0 :(得分:8)
我为类“ A”定义了关系运算符<,然后当我创建A对象的向量并比较这两个向量时会崩溃吗?!
您在这里选择了一个不好的情况,如果您使用return false;
,那应该没问题,因为它只是意味着A
的所有实例都彼此相等。 return true;
使其成为不好的运算符。
程序在GCC上运行良好,但在Msvc ++ 14上崩溃了
否,它不能正常运行。未定义行为的问题是,在您更改甚至不相关的内容之前,程序似乎无法正常工作的一种不幸行为。就像更改编译器,甚至更改相同版本或编译器优化级别的版本一样。
现在,它可以正常运行,并且程序不会崩溃!这是MSVC ++中的一些限制吗?
这不是发生的限制。 C ++中的编译器没有义务确保程序员没有创建UB,这是程序员的工作,而不是创建它,这是效率的代价。甚至更多的编译器可能会认为没有UB,并且在某些情况下,由于这种情况,一些代码已被删除。
答案 1 :(得分:3)
在
class A {
public:
explicit A(int){}
bool operator<(const A&)const {
return true;
}
};
比较器太简单了,它使A
一个更复杂的示例
class A {
int x;
public:
explicit A(int val):x(val) {}
bool operator<(const A& cmp)const {
return x < cmp.x; // for simplicity
}
};
将证明Asker试图测试的重点。
我在C ++标准中找不到任何需要operator <
进行逻辑实现的地方(这并不意味着没有。)该文档很长,是为高级多类程序员/律师编写的)。这当然不需要在编译时进行验证和诊断,否则我们将看到来自编译器的错误消息或警告。我认为在编译器级别进行测试不是可取的,因为支持它的代码复杂性将是噩梦。
C ++的标准排序功能确实需要比较功能sensible behaviour中的as do containers(特别是 [tab:container.opt] ),但是不需要诊断并且可能未经过诊断上面的原因。 Visual Studio的运行时检查非常有用,他们正在抛出程序员来帮助捕获可能导致A与B交换,然后再永久交换回来的错误,从而导致排序算法出现无限循环或堆栈溢出。
在更实际,更不合法的级别上,未提供小于结果的小于运算符违反了Law of Least Surprise,将导致代码混乱,并且经常被错误地使用,以至于值得。通常,过载的操作员应该执行期望的操作。没事也没事。