【发布时间】:2011-09-23 18:50:23
【问题描述】:
假设我的集合中有一个自定义类型,只有当所有项目在某个属性上具有相同的值时,集合/排序才有意义......如果插入具有不同值的项目,则模型被搞砸了,我想要保护它。
我想也许比较函数可能是我们可以测试它(作为断言或异常)的地方,以标记问题和/或防止插入项目。例如,在 TypeName 上,如果重要属性不相等,则 operator
这样合理吗?
【问题讨论】:
假设我的集合中有一个自定义类型,只有当所有项目在某个属性上具有相同的值时,集合/排序才有意义......如果插入具有不同值的项目,则模型被搞砸了,我想要保护它。
我想也许比较函数可能是我们可以测试它(作为断言或异常)的地方,以标记问题和/或防止插入项目。例如,在 TypeName 上,如果重要属性不相等,则 operator
这样合理吗?
【问题讨论】:
我猜将它放在比较器中可能会出现问题,因为您无法保证何时调用它。当项目数量很少并且直到稍后才调用比较器时,也许某些神话实现将项目存储在列表中?
可能最简单的方法是将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
}
【讨论】:
如果您的std::set 是自定义类的实现细节,那么应该由您的类的公共成员函数来确保不会在您的集合中插入无效元素。否则,如果您需要一个数据结构来传递对象集合,请改用std::map,为您的类提供一个密钥生成函数并将您的错误检测代码放在那里。
请记住,作为映射键的集合元素在其顺序方面应该是不可变的;基于可变状态的排序闻起来很糟糕。
【讨论】:
operator< 的想法听起来有点可疑。这仅仅意味着这些元素是最后排序的。 x 是最大元素 iff x<y==false 对于所有 y,并且 x<x==false 必须始终保持。但如果你能接受,那就没关系。
【讨论】:
当在你的操作中
恕我直言,包装并不是真正必要的,因为包装的 insert() 的行为可能是相同的(即抛出异常)。
唯一可能使包装更有吸引力的是不确定您的标准库实现是否足以应对抛出比较器。我怀疑许多标准库实现在该操作中的异常安全性是否很强。
【讨论】:
if an exception is thrown by an insert() function while inserting a single element, that function has no effects. - 这也不难实现:在确定新项目的位置之前不要开始修改容器(并成功为其分配了节点)。