标准如何定义在评估if条件表达式时构造的临时对象的生命周期?
我查找了这些信息,并在一个例子中找到了类似的东西,在第10页的1.9美元中指出[10].(我在这里指的是新规范的最终草案.)但对我来说还是不太清楚(足够)因为Visual C++的行为不同于我对该例子的理解,所以我决定问一下.
请提供适当的规格参考.
如果你将对象命名为整个对象if(那么true块和false块都会存在,但在if结束前会被销毁).
例如:
if ( MyClass x = f() ) { /* ... */ } else { /* ... */ }
nextInstruction();
Run Code Online (Sandbox Code Playgroud)
x可以在两个if块中使用但在nextInstruction被调用之前被销毁.
但如果你不说出来怎么办?
if ( f() ) { /* ... */ } else { /* ... */ }
nextInstruction();
Run Code Online (Sandbox Code Playgroud)
在我对规范的引用部分的理解中,返回的值f()将在执行进入其中一个块(for true或for false)之前被销毁.
但是,Visual C++会破坏该临时对象,就像它被命名一样.(编辑:正如Tino Didriksen所指出的,Visual C++在这里运行良好.现在我确实也确认了.在查看初始测试结果时我肯定犯了错误!)
这在某些边缘情况下很重要(不要在这里讨论它们有多可能或者以这种方式编写代码是否合适......).
例如,让我们:
class ScopedLock {
public:
~ScopedLock() { if ( isLocked() ) unlock(); }
operator bool() const { return isLocked(); }
/* ... */
};
Run Code Online (Sandbox Code Playgroud)
现在,如果我们有以下代码:
if ( ScopedLock lock = resource.lock() ) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
我们可以肯定,当执行进入true块时,我们拥有资源,并且在我们离开该块之前它将不会被解锁.
但如果有人这样写的话怎么办:
if ( resource.lock() ) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
现在至关重要的是,临时的析构函数ScopedLock将被调用.因为它确定此代码是否正确(在资源使用方面).(再次让我们一起讨论编写这样的代码是否总体上是坏的.这不是这个问题的重点...)
Tin*_*sen 10
但是,Visual C++会破坏该临时对象,就像它被命名一样.
不,不......
鉴于代码
#include <iostream>
struct S {
S() { std::cout << "S()" << std::endl; }
S(const S&) { std::cout << "S(const S&)" << std::endl; }
~S() { std::cout << "~S()" << std::endl; }
operator bool() const { return true; }
};
int main() {
std::cout << "main 1" << std::endl;
if (S s = S()) {
std::cout << "if 1" << std::endl;
}
else {
std::cout << "else 1" << std::endl;
}
std::cout << "main 2" << std::endl;
if (S()) {
std::cout << "if 2" << std::endl;
}
else {
std::cout << "else 2" << std::endl;
}
std::cout << "main 3" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
GNU g ++ 4.5.1和g ++ 4.7.0以及VC++ 2010和VC++ 2012具有完全相同的输出:
main 1
S()
if 1
~S()
main 2
S()
~S()
if 2
main 3
Run Code Online (Sandbox Code Playgroud)
在条件结束时销毁if/else和unnamed临时文件后销毁命名临时文件的位置.
据我所知,Visual C++在这方面是错误的.
实际上,临时(几乎总是)在创建它的完整表达式的末尾被销毁:
§12.2/ 3:[...]临时对象作为评估全表达式的最后一步被销毁,该表达式(词法上)包含创建它们的点
查看选择语句(if和switch)的定义,我们可以看到条件是一个表达式:
§6.4:
selection-statement:
if ( condition ) statement
if ( condition) statement else statement
switch ( condition ) statement
condition:
expression
type-specifier-seq declarator = assignment-expression
Run Code Online (Sandbox Code Playgroud)
因此,在执行以下语句之前,应该销毁在条件中创建的任何临时值(除非绑定到const-to-const).
在条件中引入新名称时的行为在§6.4/ 3中指定:
条件[...]中的声明引入的名称在其声明范围内,直到由条件控制的子语句结束.
所以在你的例子中,x是在两个分支的范围内if,并在评估之前销毁nextInstruction().