Question

C++

I'm trying to see how const references prolong the lifetime of temporaries. I'm running the code from the snippet in one of the answers to What are the differences between pointer variable and reference variable in C++? and got conflicting results between VC11 and g++ 4.8. I've expanded the snippet here:

#include <stdio.h>

struct scope_test
{
    ~scope_test() { printf("scope_test done!\n"); }
};

int main()
{
    const scope_test& test = scope_test();
    printf("in scope\n");
}

The answerer got the result:

in scope
scope_test done!

I tried it in VC11 and got this:

scope_test done!
in scope
scope_test done!

I assumed the VC11 result was caused by a lack of copy elision, so I tried to see if disabling copy elision on g++ with fno-elide-constructors would give the same result as VC11. (I don't think copy elision can be toggled in VC11.) But, g++ gives the answerer's result regardless of the setting of the flag.

The C++11 Standard, ISO/IEC 14882:2011(E), §12.2/4 and /5 states:

There are two contexts in which temporaries are destroyed at a different point than the end of the full-expression...

The second context is when a reference is bound to a temporary. 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:

...

Does the VC11 result have anything to do with copy elision? Is it a VC11 bug?

The answerer states:

temporaries assigned to const references live until the const reference goes out of scope

The list of exceptions to §12.2/5 don't rule out a non-const reference. What am I missing from the Standard?

Removing the const in VC11 produces the same result as the VC11 one with the const. Removing the const in g++ gives error: invalid initialization of non-const reference of type ‘scope_test&’ from an rvalue of type ‘scope_test’. Why is there a difference?

EDIT:

I added copy and move constructors and tried:

#include <stdio.h>

struct scope_test
{
    scope_test() { printf("regular ctor\n"); }
    scope_test(const scope_test& src) { printf("copy ctor\n"); }
    scope_test(scope_test&& src) { printf("move ctor\n"); }
    ~scope_test() { printf("scope_test done!\n"); }
};

int main()
{
    const scope_test& test= scope_test();
    printf("in scope\n");
}

Regardless of the toggling of copy elision, g++ gives:

regular ctor
in scope
scope_test done!

VC11 gives the same thing, even if the const is removed. If the const is removed from g++, g++ still gives error: invalid initialization of non-const reference of type ‘scope_test&’ from an rvalue of type ‘scope_test’.

Was it helpful?

Solution

Both behaviors are correct, certainly according to the C++03 standard (8.5.3 [dcl.init.ref] paragraph 5):

Otherwise, the reference shall be to a non-volatile const type (i.e., cv1 shall be const). [Example: ...]

  • If the initializer expression is an rvalue, with T2 a class type, and “cv1 T1” is reference-compatible with “cv2 T2,” the reference is bound in one of the following ways (the choice is implementation-defined):

    — The reference is bound to the object represented by the rvalue (see 3.10) or to a sub-object within that object.

    — A temporary of type “cv1 T2” [sic] is created, and a constructor is called to copy the entire rvalue object into the temporary. The reference is bound to the temporary or to a sub-object within the temporary.

I think the definition of C++11 still allows the copy to be made but the wording doesn't as clearly allow the copy. In any case, VC++ doesn't claim to be fully C++11 compliant.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top