You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Lambda函数中向std::vector批量添加元素触发读访问违例的问题及解决

读访问违例问题分析与解决

问题现象

运行代码时触发读访问违例:

Exception thrown: read access violation.
_My_data was 0xFFFFFFFFFFFFFFE7.

当在Lambda函数中循环向std::vector<Bullet>添加10个Bullet对象时出现该异常,但仅添加1个对象时可正常运行。

触发异常的代码

b.setOnAction([&](Bullet* b)
{
    for (int j = 0; j < 10; j++)
    {
        Bullet b1;
        b1.init();
        bullets.push_back(b1);
    }
}
);

可正常运行的代码

b.setOnAction([&](Bullet* b)
{
    Bullet b1;
    b1.init();
    bullets.push_back(b1);
}
);

Bullet类定义

setOnAction用于为Bullet类内部的std::function<void(Bullet*)>类型变量赋值,该变量会在update函数中被调用,类定义如下:

class Bullet
{
private:
    std::function<void(Bullet*)> mOnAction;

public:
    
    void setOnAction(std::function<void(Bullet*)> func) { mOnAction = func; };

    void init()
    {
        mOnAction = [](Bullet* b) {};
    }

    void update()
    {
        mOnAction(this);
    }
};

main函数代码

bullets是存储Bullet对象的std::vector,main函数代码如下:

int main()
{
    std::vector<Bullet> bullets;

    for (int i = 0; i < 10; i++)
    {
        Bullet b;
        b.init();
        b.setOnAction([&](Bullet* b)
            {
                for (int j = 0; j < 10; j++)
                {
                    Bullet b1;
                    b1.init();
                    bullets.push_back(b1);
                }
            }
        );
        bullets.push_back(b);
    }

    while (true)
    {
        for (int i = bullets.size() - 1; i >= 0; i--)
        {
            Bullet& b = bullets[i];
            b.update();
        }
    }
    return 0;
}

问题原因

std::vector的push_back操作在容器容量不足时,会重新分配一块更大的内存空间,并将原有元素拷贝/移动到新内存中,这会导致原有元素的引用、迭代器全部失效。

在main函数的循环中,通过Bullet& b = bullets[i]获取了容器中元素的引用,随后调用b.update()触发Lambda执行,而Lambda中多次调用bullets.push_back(b1)很容易触发vector扩容,此时之前获取的b引用就变成了悬空引用。后续访问该引用指向的mOnAction时,就会触发读访问违例。

仅添加1个对象时,vector可能刚好未达到扩容阈值,因此引用未失效,代码可正常运行。

解决方法

通过创建临时std::vector<Bullet>先存储新创建的Bullet对象,在遍历主容器完成后,再批量将临时容器中的元素转移到主容器中,避免在遍历过程中修改主容器导致引用失效。代码示例如下:

// 临时容器,与主容器bullets并列创建
std::vector<Bullet> bulletsToAdd;

b.setOnAction([&](Bullet* b)
{
    for (int j = 0; j < 10; j++)
    {
        Bullet b1;
        b1.init();
        // 将新对象添加到临时容器
        bulletsToAdd.push_back(b1);
    }
}
);

while (true)
{
    // 将临时容器中的所有元素批量添加到主容器
    for (auto& b : bulletsToAdd)
        bullets.push_back(b);
    // 清空临时容器,准备下一轮使用
    bulletsToAdd.clear();

    for (int i = bullets.size() - 1; i >= 0; i--)
    {
        Bullet& b = bullets[i];
        b.update();
    }
}

内容的提问来源于stack exchange,提问作者Momoyon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 06:05:21