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