2016-03-06 47 views
-1

下面是我想要做的一个抽象。主函数依次调用f1f2。在F1,构建一个局部变量,然后调用与,其中回调捕获的 const引用无阻塞功能。在执行回调之前,f1可能已经返回,t被销毁。我认为在这种情况下,回调在被调用时将保持无效的t。我写了一个测试来模拟f2在执行回调之前完成的情况。看起来很好。我误解了任何有关C++的内容吗?C++可变生命时间

void Main() { 
    f1(); 
    f2(); 
} 

void f1() { 
    T t(...); 
    nonBlocking(t, Closure(callback, t)); 
}  

void callback(const T& t) { 
    // do something with t 
} 

struct T { 
    int* a; 
    string* b; 
    ... 
} 
+1

也许代码* happend *工作正常。 – MikeCAT

+0

我写了一个测试来模拟这种情况,其中f2在回调执行之前完成。看起来很好。 – Gaga

+0

你真幸运。你是nonBlocking函数可能仍然看到“T”,因为没有其他东西覆盖它。 t上的析构函数在超出范围时运行。任何事情都可能发生在这一点上。 –

回答

1

不,您的理解是正确的。你必须避免这种错误的原因是他们使代码不可预测。正如预期的那样,您已经证明了这一点,因为它无法预测代码的行为。

1

该代码可能看起来工作正常,但这真的只是一个幻想,可能随时粉碎。

会发生什么是T存在于堆栈上。一旦f1返回,该空间是免费的,可用于其他事情。在这一点之后使用悬挂引用是未定义的行为,虽然这可能意味着它偶尔会起作用,但也可能意味着它会以任何方式随机失败。

换句话说,不要这样做。

+0

我喜欢这个答案,因为它更清楚地说明它为什么有时可以正常工作。当't'超出范围并被销毁时,对于许多类型的'T'(读取:POD类型)和许多编译器/优化设置,销毁是无操作的。因此,如果没有内容在内存中写入该位置,则回调中捕获的引用看起来像仍指向有效的“t”值。当然,一旦你让你的程序变得更加复杂,这里可能会出现令人讨厌的错误。 –

+0

谢谢。在我看来,只是在技术上正确地喊出“未定义的行为”,在理解方面确实没有什么帮助,最后机器仍然是确定性的,所以虽然语言可能没有定义任何类型的行为,但机器肯定会的。因此,尽管UB存在可怕的威胁,事情可能实际上仍然有效......直到有些事情发生变化(并且它可能不是你所期望的),事情就会停止。解释为什么发生这种情况可能有助于人们了解正在发生的事情,以及为什么他们不应该这样做。 –