为什么不能比较自定义类类型的两个向量?

时间:2019-08-12 22:05:56

标签: c++ vector

我正在使用一个向量,其类类型为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 ++中有一些限制吗? (我的意思是正确定义运算符?)

2 个答案:

答案 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,将导致代码混乱,并且经常被错误地使用,以至于值得。通常,过载的操作员应该执行期望的操作。没事也没事。