1

我知道这是有问题的,但我很好奇这样做是否会导致未定义的行为?

class A
{
public:
    int i;
};
class As {
public:
    bool operator()(const A* l, const A* r)
    {
        return l->i < r->i;
    }
};
int main() {
    std::set<A*,As> s;
    A* a1 = new A();
    a1->i = 9;
    A* a2 = new A();
    a2->i = 2;
    s.insert(a1);
    s.insert(a2);
    for(std::set<A*,As>::iterator i = s.begin(); i != s.end(); ++i)
        std::cout<<(*i)->i<<std::endl;
    for(std::set<A*,As>::iterator i = s.begin(); i != s.end(); ++i)
    {
        if((*i)->i == 2)
            (*i)->i = 22;
    }
    for(std::set<A*,As>::iterator i = s.begin(); i != s.end(); ++i)
        std::cout<<(*i)->i<<std::endl;
    //now s is in incorrect state, insert all elements into a tmp one
    std::set<A*,As> t;
    for(std::set<A*,As>::iterator i = s.begin(); i != s.end(); ++i)
        t.insert(*i);
    s.swap(t);
    for(std::set<A*,As>::iterator i = s.begin(); i != s.end(); ++i)
        std::cout<<(*i)->i<<std::endl;
}

输出是:

2
9
22
9
9
22

由 GCC 4.7 编译时似乎工作正常,但我不知道这是否只是运气。

4

1 回答 1

3

标准 (C++11) 说明了关联容器中使用的键比较函数,即容器,例如std::set

(§23.2.4/3)[...] 对于同一容器中的任意两个键,调用k1应始终返回相同的值。k2comp(k1,k2)

Therecomp指的是比较功能,在您的情况下是 functor As()

Clearly, when the keys contain pointers to external objects and the result of calling comp(k1,k2) depends on those external objects, then modifying the objects causes the rule above to be violated.

The Standard doesn't say what happens if you violate this rule. So, formally speaking, you have undefined behaviour then (because the Standard leaves the behaviour undefined).

In practice, I guess there is a significant chance that terrible things, including segmentation faults, could happen as a result of a violation, because the next time the set is searched for a key, or an insert is made, the search algorithm – built on the assumption that the keys are in order – might go astray and make out-of-bounds accesses and the like.

So the conclusion is that, yes, this is UB, and can cause bad things to happen even if it works in a few selected cases in practice.

于 2013-06-01T08:50:00.640 回答