• C++避坑:避免在循环遍历容器时,在循环体内删除、增加元素


    随着业务的增长,循环体可能会逐渐复杂起来。

    我们通常遍历一个容器,对其中的每一个元素执行方法,从而更新它们的状态。随着代码逐渐复杂,我们在写新的方法时,可能并没有意识到this正处于循环遍历当中。此时若对容器进行大小的修改,即增加元素或删除元素,是一个危险的行为。

    对于 std::vector ,如果这样写:

    std::vector<Foo> vfoo;
    // ...
    for (auto it = vfoo.begin(); it != vfoo.end(); ++it)
    {
    	// do something
    	// add Foo to vector
    }
    

    由于对vector增加元素可能导致重新分配容器内存,因此分配之后旧的迭代器会失效,此时it不能再使用,否则会有未定义的行为。而删除it所指的对象同样会导致it失效。

    即便是对于原生数组,我们也要注意。假如我们有这样的数组元素:

    Foo *foo = new Foo;
    foo_list[index] = foo;
    

    foo_list 管理着动态分配的Foo对象,现在遍历它:

    for (int i = 0; i < MAX_ITEM_COUNT; ++i)
    {
    	foo_list[i]->Update();
    }
    

    在Foo::Update中有这样的代码:

    void Foo::Update()
    {
    	if (...) m_foo_list->Remove(key);
    
    	this->OtherMemberFunction();
    }
    

    m_foo_list->Remove(key); 令遍历它的容器foo_list delete掉某一个对象,这个对象可能是别的对象,也可能是this对象,而接下来,访问其成员则是未定义的行为。

    在成员函数中把this删掉看起来比较奇怪,但的确有可能发生。

    我们避免在循环中错误地修改容器的一个解决方案就是,延迟删除,即设置一个标记,在循环开始或结束的时候,对设置标记的元素进行统一删除处理。

    或者,对于简单的遍历操作,可以采用如下惯用法删除:

    std::map<key, value> kvmap;
    for (auto it = kvmap.begin(); it != kvmap.end(); )
    {
    	if (...)
    	{
    		// ...
    		it = kvmap.erase(it);
    	}
    	else
    	{
    		++it;
    	}
    }
    
  • 相关阅读:
    pycharm快捷键、常用设置、包管理
    【转载】TCP socket心跳包示例程序
    【转载】C++定时器实现
    金龙一卡通登陆爬取数据 免验证码 多线程 学生卡 CAUC
    python3 正方教务系统 爬取数据
    29、Python之Web框架Django入门
    28、Python之前端组件学习
    27、Python之jQuery基础
    26、Python之JavaScript进阶篇
    25、Python之JavaScript基础
  • 原文地址:https://www.cnblogs.com/demon90s/p/15689677.html
Copyright © 2020-2023  润新知