我无法理解为什么以下代码不会崩溃。
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 变为空或无效?
答案 0 :(得分:1)
[MyObj]() { }
不会通过引用捕获指针MyObj
,而是通过值捕获。这意味着MyObj
的值将在创建lambda时复制。因此,即使将MyObj
设置为nullptr,lambda仍将使用其原始值,该原始值仍指向内存中的同一区域。
在调用lambda时,*MyObj
中的对象已被删除,所有0xdd
字节都可以看到(至少在调试模式下)。
如果您要编写[&MyObj]() { }
,则MyObj
将被捕获为引用,这意味着lambda将始终使用捕获的指针的当前值。在这种情况下,行为应完全符合您的预期:lambda中的nullptr检查将失败,并且不会调用Hello()
。
关于您的后续问题:传递this
的作用与其他任何符号一样。通过值传递它会创建一个副本,该副本将始终允许您访问该对象,即使该对象的生命周期结束(由此带来的所有风险)。只要this指针有效,就可以通过引用传递它,只要该方法的范围有效,它就可能有效。