I was shown the following example in chat:
#include
struct foo { ~foo() { std::cout << \"destroying!\\n\"; } };
const foo& func(co
This is subject of two issue reports, http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1299 and http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1568 .
The former issue report, of which I am the reporter, was intended to cover all these cases where a reference is bound to a temporary object, but is not intended to be lifetime-extending. The description in the body of the issue only mentions prvalues being confused with temporary expressions (that actually decide whether lifetime of what they evaluate to is lengthened or not). But lvalue and xvalues are likewise confused with these in the Standard. An example where that happens in the context of static_cast
is issue number #1568 (in which the use of "temporary variable" further confuses the matter).
Actually, this:
A temporary bound to a reference parameter in a function call (5.2.2) persists until the completion of the full-expression containing the call.
Contradicts the other rules in the same paragraph. Because the temporary is bound to both a reference parameter in a function call and to a local automatic reference variable.
You're almost right. This behaviour actually comes from the function call specifically, not because of any sort of "only works once" rule.
Here's the wording for the whole lifetime extension "feature", with the pertinent rule emphasised in bold:
[C++11: 12.2/5]:
[..] The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except:
- [..]
- A temporary bound to a reference parameter in a function call (5.2.2) persists until the completion of the full-expression containing the call.
- [..]
Probably I am a bit slow but to me it did not become clear what the resolution of this question is from reading the other answers. Thus I modified the code shown and wanted to summarize for others: the answer is, you get undefined behavior if you access y
!
Run this code:
struct foo {
int id;
foo(int id) : id(id) { std::cout << "ctor " << id << std::endl; };
~foo() { std::cout << "dtor " << id << std::endl; }
};
const foo& func(const foo& a, const foo&) { return a; }
int main(int argc, char** argv) {
foo x(1);
const foo& y = func(foo(2), x);
std::cout << "main " << y.id << std::endl;
return 0;
}
The output for me is:
ctor 1
ctor 2
dtor 2
main 2
dtor 1
But the line main 2
is undefined behavior.
The rule which applies here is common sense. The standard is poorly worded, and does in fact guarantee this. But there's no practical way to implement it.