This outputs F~ but I was expecting ~F

#include <iostream>

struct Foo {
    int _x;
    operator const int & () const {return _x;}
    ~ Foo () {std :: cout << "~";}
};

void foo (const int &)
{
    std :: cout << "F";
}

int main ()
{
    foo (Foo ());
}

I constructed this as a counterexample to show that the most-important-const is an exception rather than a rule. It is normally written as

when a const reference binds to a temporary, then the lifetime of that temporary is extended to the lifetime of the reference

I was trying to illustrate that, although Foo() is a temporary, the reference to _x returned by the conversion operator is not, and that the above code is unsafe.

But the output seems to prove that the example is safe, the lifetime of the temporary Foo() is extended by the existence of a const reference to one of its members.

Is this right? Where in the standard is this specified?

有帮助吗?

解决方案

The general rule, regarding temporaries, is that their life ends when the full expression they are part of ends (informally, when reaching the ;).

12.2 Temporary objects

3/ [...] Temporary objects are destroyed as the last step in evaluating the full-expression (1.9) that (lexically) contains the point where they were created. This is true even if that evaluation ends in throwing an exception. The value computations and side effects of destroying a temporary object are associated only with the full-expression, not with any specific subexpression.

其他提示

That's because the temporary survives for the whole duration of function call. When you do foo (Foo ()); here's what happens:

  1. temporary Foo is contructed, then
  2. operator const int& is called on the temporary
  3. foo() is called and this outputs F
  4. once foo() returns temporary Foo is destroyed and this outputs ~

There's no magic here. All function arguments live in the scope of the caller, including temporaries. The temporary Foo() is constructed in the scope of the caller, and destroyed at the end of the line.

So whatever the function foo() does happens before its arguments in main() are destroyed.

But your Foo instance here was always going to live until the semicolon ending the statement in which it was created. Passing a reference to a member into a function call didn't change that.

Try:

int const &ref = Foo();
foo(ref);

versus

Foo const &ref = Foo(); // or function returning temp
foo(ref);
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top