1) Is it undefined behavior to return a reference to a temporary, even if that reference is not used? For example, is this program guaranteed to output \"good\":
<
2) Is it undefined behavior to simply have a reference to an object that no longer exists, even if that reference is not used?
No. The rule that references must refer to a valid object applies when the reference is inintialised. The rule has already been quoted in the comments: "A reference shall be initialized to refer to a valid object or function." This rule has not been violated in your program, and there are no other restrictions on references requiring them to refer to valid objects or functions after initialization.
The standard has a few examples involving dangling references, such as [class.temporary]5.4:
struct S { int mi; const std::pair<int,int>& mp; }; S a { 1, {2,3} }; S* p = new S{ 1, {2,3} }; // Creates dangling reference.
and doesn't say for any such example that the mere existence of a dangling reference is invalid. Although it's never explicitly stated as allowed, the absence of any rule prohibiting it is enough to allow it.
1) Is it undefined behavior to return a reference to a temporary, even if that reference is not used?
No. The construction of the result (the initialisation of the reference) happens in the context of the called function. There can even be extra code in the called function that runs after the construction of the result: destructors for local objects run after the construction of the result has finished. Since the reference is initialized to a valid object, this is just like your second question, that same rule still hasn't been violated.
3) Is it undefined behavior to combine these?
Yes. In your example, p
is not initialised to refer to a valid object or function. As you can tell from the comments on your question, there are issues with the wording in the standard, but the intent of this rule pretty clearly is that if it is violated, the behaviour is undefined.
I don't see any rules that forbid case 1 and 2 nor can I find a relevant defect report either.
All we really have from the draft C++ standard is from section 8.3.2
[dcl.ref]:
[...]A reference shall be initialized to refer to a valid object or function. [ Note: in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the “object” obtained by indirection through a null pointer, which causes undefined behavior.[...]
which does not apply to case 1 since we are not initialing a reference and neither case 2 since the object is valid when we initialize the reference.
This does seem to apply to case 3. So what does valid object mean is subject of the following defect report. The defect report which covers this topic is still open and therefore we can only get a a feel for current thinking which is that this should be undefined behavior.
If we look at defect report 453: References may only bind to “valid” objects , which deals with what it means to bind a reference to an invalid object. The current proposed resolution says:
[...]If an lvalue to which a reference is directly bound designates neither an existing object or function of an appropriate type (8.5.3 [dcl.init.ref]), nor a region of storage of suitable size and alignment to contain an object of the reference's type (1.8 [intro.object], 3.8 [basic.life], 3.9 [basic.types]), the behavior is undefined. [...]
So we can say the current thinking is that this should be undefined behavior but currently this is defect and so we can't say for sure until this defect report is resolved. I would err on the side of caution and assume it is undefined behavior.