据我了解,此lambda调用应该无效,但不会崩溃。为什么?

时间:2019-02-13 01:52:48

标签: c++11 lambda

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

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(),并且没有崩溃。

后续问题: 在我通过 this 作为捕获的lambda中,有没有机会在调用lambda时 this 变为空或无效?

1 个答案:

答案 0 :(得分:1)

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

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

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

关于您的后续问题:传递this的作用与其他任何符号一样。通过值传递它会创建一个副本,该副本将始终允许您访问该对象,即使该对象的生命周期结束(由此带来的所有风险)。只要this指针有效,就可以通过引用传递它,只要该方法的范围有效,它就可能有效。