• 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;
    	}
    }
    
  • 相关阅读:
    [Unity3D] 如何将飞飞游戏资源提取并加载到uinty3d中
    [Unity3D] 解决提示参数动作文件不存在的错误Parameter 'XXX' does not exist.
    [Unity3D] 字体垂直自动滚动&鼠标拖拽滑动字体滚动
    [Unity3D] 图集按照顺序显示(幻灯片效果)&指定间隔时间显示
    [Unity3D] 在UI界面上显示播放视频
    TypeScript
    Css 设置超过再两行显示省略号
    vue scss 样式穿透
    JavaScript 严格模式(strict mode)
    Webpack file-loader 和 url-loader
  • 原文地址:https://www.cnblogs.com/demon90s/p/15689677.html
Copyright © 2020-2023  润新知