根据我的理解,这个lambda调用应该是无效的,但它不会崩溃。为什么?

问题描述 投票:1回答:1

我无法理解为什么以下代码不会崩溃。

class MyClass
{
public:
    MyClass() {    m_contents = 0xF0F0F0F0; }
    void Hello() { printf("Hello, address: %llx, contents: %x, size: %d\n", (long long int)this, m_contents, sizeof(MyClass)); }
    int m_contents;
};

int main()
{
    MyClass* MyObj = new MyClass();
    MyObj->Hello();

    auto MyLambda = [MyObj]()
    {
        if (MyObj != nullptr)
        {
            MyObj->Hello();
        }
    };

    memset(MyObj, 0, sizeof(MyClass));
    MyObj->Hello();
    delete MyObj;
    MyObj = nullptr;

    MyLambda();

    return 0;
}

这是输出:

Hello, address: 1ddb4a16100, contents: f0f0f0f0, size: 4
Hello, address: 1ddb4a16100, contents: 0, size: 4
Hello, address: 1ddb4a16100, contents: dddddddd, size: 4

我本来期望lambda调用崩溃,因为我擦除了用于调用Hello()函数的所有内存。我知道内容被擦除,因为m_contents变为0.调用delete后,m_contents变为随机值,但仍然调用Hello()并且没有崩溃。

后续问题:在一个lambda中,我把它作为一个捕获传递给它,是否有可能在lambda被调用时变为null或无效?

c++11 lambda
1个回答
1
投票

[MyObj]() { }不通过引用捕获指针MyObj,而是通过值捕获。这意味着MyObj的值将在创建lambda时被复制。因此,即使将MyObj设置为nullptr,lambda仍将使用其原始值,该值仍然指向内存中的相同区域。

在调用lambda时,*MyObj中的对象已被删除,所有0xdd字节都可以看到(至少在调试模式下)。

如果您要编写[&MyObj]() { },那么MyObj将被捕获作为参考,这意味着lambda将始终使用捕获指针的当前值。在这种情况下,行为应该与您预期的完全一样:lambda中的nullptr检查将失败,并且不会调用Hello()

至于你的后续问题:传递this确实与任何其他符号没有区别。按值传递它将创建一个副本,该副本将始终允许您访问该对象,即使在其生命周期之后(由此产生的所有风险)。只要该指针有效,通过引用传递它将起作用,这可能只要方法的范围有效。

© www.soinside.com 2019 - 2024. All rights reserved.