首页 > 解决方案 > C++:读取 Lambda 捕获的指针时发生访问冲突

问题描述

我不会假装我对 lambdas 非常有经验,但是对于这个看似简单的问题,我认为我需要更深入地了解它的实际工作原理。

我在外部范围内实例化一个对象,并使用 2 个 lambda,我尝试修改该指针。

// Object to be manipulated
Object* obj= nullptr;

// To be invoked externally in order to construct and initialize obj
std::function<void(std::function<void(const String&)>)> SetObject
    = [&obj](std::function<void(const String&)> func) 
{
    obj= new Object();
    // ... Initialize Values
};

// To be invoked externally to reset and delete obj
std::function<void()> ResetObject
= [&obj]() 
{
    if(obj)
    {
        delete obj;
        obj= nullptr;
    }
};

主代码在创建新的 Object 实例之前执行并首先调用RESET方法。假设“主”代码无法访问、读取或修改 obj - 因此依赖于盲重置。

预期结果:第一次调用重置表达式时,对 obj 的检查应该返回 false,因为 obj 在外部范围内被设置为 nullptr - 没有任何反应。

实际结果:执行reset时,obj不再指向NULL,检查返回true并调用delete,导致访问冲突。

我想知道我尝试做的任何事情是否都是无效的操作,或者我捕获变量的方式是否不正确。我尝试按值捕获指针,将函数设置为可变,并且出于绝望将引用和值捕获相结合。

编辑:在这一点上,我相信对象的范围是其他人指出的罪魁祸首。考虑到这一点,我将尝试解决方法并报告。

标签: c++lambda

解决方案


虽然我们不能仅从您的示例中看出,但我怀疑obj可能是一个局部变量,在被捕获后超出了范围。解决此问题的一种方法是添加另一个间接级别:

Object** objptr = new Object*();

std::function<void(std::function<void(const String&)>)> SetObject
    = [objptr](std::function<void(const String&)> func) 
{
    *objptr = new Object();
};

std::function<void()> ResetObject
= [objptr]() // Note we are now capturing objptr by value
{
    if(*objptr)
    {
        delete *objptr;
        *objptr = nullptr;
    }
    // Is objptr reused by another call to SetObject?
    // If not, delete it here as well.
    // delete objptr;
};

推荐阅读