2011-10-04

在STL容器中删对象一定要小心

先来看一段代码:
typedef map<string, string> Dict;
Dict eventmap;
for (Dict::iterator pIter = eventmap.begin(); pIter != end(); ++pIter)
{
    if (pIter->second == "no")
        eventmap.erase(pIter);
}
熟悉STL的人都知道,这段代码是错的。出问题的可能性不是100%,但是相当大,而且可能会是那种不一定能稳定重现的问题,往往会搞得人很恍惚。

自己很早以前就吃过这个亏,那时候还不太会用STL。当定位到这一段代码后,凭直觉也觉得如果这样删除对象,那删除之后的pIter是不是正确的?可能很难讲。毕竟学过「数据结构」,大概能猜到各种容器里面的信息是如何组织的。

昨天又看见同事在这样写代码。可能他对STL也不熟。至少我目前对于erase这个单词已经产生了足够的警戒,一旦要用的时候就会想起吃过的亏来。

正确的代码应该是:
typedef map<string, string> Dict;
Dict eventmap;
for (Dict::iterator pIter = eventmap.begin(); pIter != end();)
{
    if (pIter->second == "no")
        pIter = eventmap.erase(pIter);
    else
        ++pIter;
}
另外,昨天发现Borland C++ Builder提供的STL和VC有点区别,map::erase没有返回值,因此不支持这种写法。那么还有另一种办法:
eventmap.erase(pIter++);
这样就可以了。相比之下,这种写法可能适应性更强一些。

没有评论:

发表评论