C++ 检测插入到std::集合中的错误项

C++ 检测插入到std::集合中的错误项,c++,algorithm,stl,C++,Algorithm,Stl,假设我的集合中有一个自定义类型,并且集合/排序只有在所有项在某些属性上具有相同值时才有意义。。。如果插入了具有不同值的项,则模型将出错,我希望对此进行保护 我认为比较函数可能是一个我们可以测试它(作为断言或异常)的地方,以标记问题和/或防止插入项。e、 在TypeName上,操作符我想把它放在比较器中可能会有问题,因为你不能保证它什么时候被调用。也许有些神秘的实现会在项目数很小时将项目存储在列表中,直到稍后才调用比较器 最简单的方法可能是将std::set封装在执行这些断言的保护性外部类中 cl

假设我的集合中有一个自定义类型,并且集合/排序只有在所有项在某些属性上具有相同值时才有意义。。。如果插入了具有不同值的项,则模型将出错,我希望对此进行保护


我认为比较函数可能是一个我们可以测试它(作为断言或异常)的地方,以标记问题和/或防止插入项。e、 在TypeName上,操作符我想把它放在比较器中可能会有问题,因为你不能保证它什么时候被调用。也许有些神秘的实现会在项目数很小时将项目存储在列表中,直到稍后才调用比较器

最简单的方法可能是将
std::set
封装在执行这些断言的保护性外部类中

class MySet {
  private:
     std::set<myFunkyType> myType;

  public:
     void insert(myFunkyType type) {
        assert(!type.isFunky(), "funk violation");
        // and so on
     }

     // all other members other than insertion or mutation just delegate to the
     // underlying set
类MySet{
私人:
std::设置myType;
公众:
无效插入(myFunkyType类型){
断言(!type.isFunky(),“funk冲突”);
//等等
}
//除了插入或变异之外的所有其他成员都只委托给
//基础集

}

我想把它放在比较器中可能会有问题,因为在调用它时,您没有任何保证。也许有些神秘的实现会在项目数很小时将项目存储在列表中,直到稍后才调用比较器

最简单的方法可能是将
std::set
封装在执行这些断言的保护性外部类中

class MySet {
  private:
     std::set<myFunkyType> myType;

  public:
     void insert(myFunkyType type) {
        assert(!type.isFunky(), "funk violation");
        // and so on
     }

     // all other members other than insertion or mutation just delegate to the
     // underlying set
类MySet{
私人:
std::设置myType;
公众:
无效插入(myFunkyType类型){
断言(!type.isFunky(),“funk冲突”);
//等等
}
//除了插入或变异之外的所有其他成员都只委托给
//基础集

}

如果您的
std::set
是自定义类的实现细节,那么应该由类的公共成员函数来确保无效元素不会插入到集合中。否则,如果您需要一个数据结构来传递对象集合,请改用
std::map
,为您的类提供一个键生成函数,并将错误检测代码放在那里


记住,集合元素作为映射键,其顺序应该是不可变的;基于可变状态的排序很糟糕。

如果您的
std::set
是自定义类的实现细节,那么应该由类的公共成员函数来确保无效元素不会插入到集合中。否则,如果您需要一个数据结构来传递对象集合,请改用
std::map
,为您的类提供一个键生成函数,并将错误检测代码放在那里


记住,集合元素作为映射键,其顺序应该是不可变的;基于可变状态的排序很糟糕。

操作符操作符当在op中检测到无法建立严格的弱排序时,唯一合理的做法是抛出异常。任何类型的插入或op<可能的其他返回都可能打破集合的内部约束

包装并不是真正必要的,因为包装的insert()的行为可能是相同的(即抛出异常)


使包装更具吸引力的唯一一件事是不确定您的标准库实现是否足够好,能够处理抛出的比较器。我怀疑许多标准库实现在该操作中是否具有强大的异常安全性。

当您在op中检测到无法建立严格的弱排序时,唯一合理的做法是抛出异常。任何类型的插入或op<可能的其他返回都可能打破集合的内部约束

包装并不是真正必要的,因为包装的insert()的行为可能是相同的(即抛出异常)


使包装更具吸引力的唯一一件事是不确定您的标准库实现是否足够好,能够处理抛出的比较器。我怀疑许多标准库实现在该操作中的异常安全性是否很强。

公共继承如何?MySet实际上是一个集合,您不必编写所有的包装函数…@yi_H:我的理解是STL容器并不是真正设计成子类的,尽管我忘记了原因。@Jeff:如果我只是想阻止它被插入,也许这不是问题,但如果我想提醒你,这是一个很好的观点。@John:这是一种编写断言的特殊方式;)那么公共继承权呢?MySet实际上是一个集合,您不必编写所有的包装函数…@yi_H:我的理解是STL容器并不是真正设计成子类的,尽管我忘记了原因。@Jeff:如果我只是想阻止它被插入,也许这不是问题,但如果我想提醒你,这是一个很好的观点。@John:这是一种编写断言的特殊方式;)我从来没有说过它是可变的。当然,拥有这个集合的控制类应该检查这个,但是我想确定一下,因为这是一种很难追踪的bug,我从来没有说过它是可变的。当然,拥有集合的控制类应该检查这一点,但我想确定一下,因为这是一种很难追踪的bug。我认为实现应该足够强大:
如果插入单个元素时insert()函数引发异常,该功能没有任何效果。
-也不难实现:在确定新项目的位置(并成功为其分配节点)之前,您不会开始修改容器。@vis