Detecting a bad item inserted into a std::set
Say I have a custom type in my set, and the set/ordering only makes sense if all items have the same value on some property... if an item with a different value is inserted the model is screwed up and I want to protect this.
I thought maybe the comparison function might be a place we could test this (as an assert or exception) to either flag the problem and/or prevent the item getting inserted. e.g on TypeName, operator<() a开发者_开发百科lways returns false if the important attribute isn't equal.
Is this reasonable?
I guess putting it in the comparator could have issues as you've not got any guarantees when it's going to be called. Perhaps some mythical implementation stores items in a list when the number of items is small and doesn't call the comparator until later?
Probably the simplest approach would be to wrap the std::set
in a protective outer class that performed these assertions.
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
}
If your std::set
is an implementation detail of a custom class then it should be up to your class's public member functions to ensure that invalid elements aren't inserted in your set. Otherwise, if you need a data structure to pass a collection of your objects around use a std::map
instead, provide your class with a key generating function and put your error detection code there.
Remember that set elements, as map keys, should be immutable with respect to their ordering; basing ordering on mutable state smells bad.
The operator<
idea sounds a bit fishy. It would merely mean that such elements are ordered last. x
is the largest element iff x<y==false
for all y, and x<x==false
must always hold. But if that's acceptable to you, it's OK.
When in your op< you detect that you can not establish a strict weak ordering, the only reasonable thing is to throw an exception. Any kind of insert, or possible other return from op< will likely break the internal constraints of the set.
Wrapping is IMHO not really necessary, since the behaviour of your wrapped insert() would probably be the same (that is, throw an exception).
The only thing that might make wrapping more attractive is any uncertainty about whether your standard library implementation is good enough to be able to cope with a throwing comparator. I doubt that many standard library implementations are strong on exception safety at that operation.
精彩评论