星期日, 八月 19, 2007

for循环中iterator不可乱删除



今天写iTalk,想要把空组删除掉。
//tree_store就是列表中的数据(TreeStore)
//下面代码作用是扫描列表中的组,发现空组则删除。
Gtk::TreeModel::Children children = tree_store->children();
Gtk::TreeModel::iterator it_g;
it_g = children.begin();

for (; it_g != children.end(); ++it_g) {
Gtk::TreeModel::Children grandson = it_g->children();
if(grandson.begin()==grandson.end())
{
const Glib::ustring& tmp= (*it_g)[buddyColumns.id];
std::cout<<tmp<<"为空组======================="<<std::endl;
tree_store->erase(it_g);
}
}

不过遇到了段错误。思前想后发现段错误的原因是因为那个删除 tree_store->erase(it_g);
执行了这句后,it_g所指向的数据已经失效,所以it_g++的话就会溢出。
把for 循环改成do while循环,用一个中间变量来得到it_g的值,并用它来删除。

do{
Gtk::TreeModel::Children grandson = it_g->children();
Gtk::TreeModel::iterator point = it_g;
it_g++;
if(grandson.begin()==grandson.end())
{
//const Glib::ustring& tmp= (*point)[buddyColumns.id];
//std::cout<<tmp<<"为空组======================="<<std::endl;
tree_store->erase(point);
}

}
while(it_g!=children.end());
嗯。这样也算是解决问题吧。

4 条评论:

zlbruce 说...

erase()会返回下一行的iterator,或者end();所以直接it_g = tree_store->erase(it_g);去掉for中的++it_g就可以了。
貌似grandson.empty()要好理解先吧

lerosua ' blog 说...

经过zlbruce提醒,代码已经精简:

while(it_g!=children.end()){
Gtk::TreeModel::Children grandson = it_g->children();
if(grandson.empty())
it_g = tree_store->erase(it_g);
else
it_g++;
}

google老犁 说...
此评论已被作者删除。
google老犁 说...

erase(iterator)会删除这个位置上的元素,所以当你调用erase(iterator)时,那么iterator位置上的元素会被删除,iterator所指的元素位置也就无效了,编译不会出错(要想编译出错的话,使用安全STL,如STL port)。所以最优雅的解决的方法是erase(iterator++),删除了当前位置的元素,iterator的位置向下移动了,所以就不会出现段错误的情况了。

考虑:
erase(iterator++)

erase(++iterator)
这两者的区别.