超出范围

时间:2017-12-20 14:41:10

标签: c++ lambda scope shared-ptr

我遇到了共享指针,lambda和范围的问题。

我的情况是我有一个我调用的方法,所以我可以稍后使用返回的值。这是正常的,直到这里。当我在这个方法中有一个异步方法时,问题出现了,我必须为shared_pointer做一组异常。我正在使用lambda函数来处理来自此异步方法的回调。在这个lambda中,我必须使用我的shared_pointer并在其上设置一个异常(来自其类的方法)resultPtr-> setException();

我首先使用了shared_ptr,然后是lambda中的weak_ptr(因为我在某些地方读到了shared_ptr可能导致内存泄漏)。但直到现在我想我真的需要使用shared_ptr。

我必须测试是否在第二个.cpp中设置了此异常,因此我调用该方法并使用返回的值。我把线程等了大约500ms然后我测试它是否有例外,但它没有。但是,在极少数情况下,它“hasException”。我可以看到lambda被调用,它通过我的日志设置异常,但它似乎没有改变我先返回的值(就像它指向不同的地方)。

我提到的第一种方法的输入对我的情况并不重要,只是它们是指针。

就我而言,我有类似的东西:

file1.cpp
typedef shared_ptr<Result> ResultPtr;
ResultPtr method_name(TypePtr args)
{
    if(args != nullptr)
    {
        ResultPtr result = make_shared<Result>();
        stuff->callAsync([this, result](input)
        {
            if(result == nullptr)
            {
                result->setException();
            }
        });
    }
    else
    {
        result->setError();
    }
    return result;
}

file2.cpp
bool testingMethod()
{
    ResultPtr result = file1::methodName(TypePtr args)
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    test(result->hasException);
}

为了测试我正在使用另一个类,我用某些输入调用这个方法(这里不重要),我需要比较resultPtr的对象值。会发生的是,一旦它超出范围(返回a),我就无法再访问该对象了。在我调用此方法之后,我将线程等待大约1秒钟,但它永远不会更改状态(因为它不能指向被破坏的对象)

无论如何要克服这个问题?其他建议?

谢谢!

3 个答案:

答案 0 :(得分:2)

当然,您无法再访问该对象,因为当destroyed离开创建它的if(args)块的范围时,它是shared pointer。你需要让对象生活在方法之外,例如: G。将其作为类成员或(&lt; deity&gt;禁止!)存储在全局变量中。

是否需要将其包装在共享指针中尚不清楚,您需要提供一个MCVE以及更清晰的what you want to achieve描述。

答案 1 :(得分:1)

如果callAsync实际上是异步的,那么当局部变量resulta超出范围时,lambda可能会开始执行。您应该将所需的变量作为参数传递,例如与std::bind绑定:

typedef shared_ptr<Result> ResultPtr;
ResultPtr method_name(args)
{
    if(args)
    {
        ResultPtr a = make_shared<Result>();
        std::weak_ptr<Result> result(a);
        stuff->callAsync(std::bind([this](std::weak_ptr<Result> result_param)
        {
            auto resultPtr = result_param.lock();
            if(resultPtr)
            {
                resultPtr->setValue()
                ...other stuff...
            }
        }, result));
    }
    else
    {
        a->setError();
    }
    return a;
}

是的,你的例子令人困惑

答案 2 :(得分:1)

如果你需要lambda来保证它保持对象存活,为什么你使用弱指针传入,而不是共享指针?弱指针的目的是你所看到的行为,它本身不会使对象保持活跃状态​​。

因为您只捕获一个弱指针,所以当唯一的共享指针超出范围时,如果它在锁定弱指针之前超出范围,则它不会使共享指针保持活动状态。但是你可以捕获共享指针(通过值,因此获取副本)而不是使用弱指针。然后引用计数将递增,并且lambda中的共享指针将使其保持活动状态,并且只有当两个共享指针都超出范围时才会删除它。

这样的共享所有权是共享指针的原因,如果希望在共享指针引用计数达到零时无法再访问该对象,则应该只使用弱指针。