在if条件表达式中构造的未命名临时的生存时间

Ada*_*ura 28 c++

标准如何定义在评估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临时文件后销毁命名临时文件的位置.


Luc*_*lle 7

据我所知,Visual C++在这方面是错误的.

实际上,临时(几乎总是)在创建它的完整表达式的末尾被销毁:

§12.2/ 3:[...]临时对象作为评估全表达式的最后一步被销毁,该表达式(词法上)包含创建它们的点

查看选择语句(ifswitch)的定义,我们可以看到条件是一个表达式:

§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().