Const Reference To Temporary Is Useless

C++ is always full of surprises. This week, I learned that C++ has (yet another) special feature that allows the lifetime of a temporary (rvalue) to be lengthen on the stack if it is bound to a reference-to-const.

It means that the following example is legal C++. In this example, the temporary i’s lifetime is extended across its original scope.

int f()
{
	int i = 0;
	return i;
}
void main()
{
	int const &cr = f(); // lifespan extended
	int &cr = f(); // illegal (crash) because f() does not return lvalue
}

This is supposed to minimize the number of copies performs.

More Ammo To Blow Your Leg Away

You would think that this feature prevents the temporary from being copied. Apparently not so.

If you run the following program on VC9.0 and VC10.0, obj destructor is called twice, implies that it was copied. [sidenote: gcc 4.3 did not perform the copy]

#include <iostream>
class obj
{
public:
	~obj() { std::cout <<"destroyed" << std::endl; }
};
void main()
{
	obj const &rco = obj();
}

This is because the standard allows the temporary to be fully copied, and renders the reference-to-const declaration useless.

Here’s the C++ standard’s guideline in section 8.5.3.

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 or to a subobject with that object

A temporary of type “cv1 T2” is created, and a constructor is called to copy the entire rvalue object into the temporary. This reference is bound to the temporary or to a subobject with the temporary.

No Better Than RVO

Dave Abraham’s copy ellision example demonstrates how smart modern compilers have become. Return Value Optimization works well in both named and unnamed temporaries, and compose nicely.

So why bother adding reference-to-const if it works just as well without it?

Final Thoughts

C++0x (C++0a?) is supposed to address this problem by enforcing the reference-to-const to always bind to the rvalue, instead of its copy. But if a copy can be elided, I expect RVO would have done it as well.

5 thoughts on “Const Reference To Temporary Is Useless

  1. I once asked Bjarne Stroustrup (in a Usenet discussion) about the rationale, and he replied that it provided uniform rules: the same rule for initializing a local reference as for initializing a formal argument reference.

    Still, as with any feature, use cases that nobody originally envisioned pop up.

    In particular the right destructor is called when you have a Base const& and initialize it with a Derived temporary.

    And this feature is used in Petru Marginean and Andrei Alexandrescu’s ScopeGuard. They published an article about it in DDJ, and that article + accompanying code code is available on the net. If you’re not familiar with ScopeGuard it’s definitely worth checking out, but note that for MSVC their use of standard __LINE__ needs to be replaced with MS-specific __COUNTER__.

    I vaguely recall seeing a ScopeGuard class added to Boost.

    Cheers,

    – Alf

  2. Groucho says:

    Weird concepts like this only proof how flawed C++ is.
    Honestly, I prefer to use C++ as just “C with classes”, without all this fuss.

  3. Andras says:

    What if your const reference is not to a temporary?
    Are you supposed to know (and assume it will never change) whether it is or isn’t a temporary?
    You should write your code without such assumptions.

  4. Matt Fisher says:

    I think the reference-to-temporary can help show intent, as well. If you want to explicitly limit yourself to just a base class’s methods, you can capture the temporary in a reference-to-base.

Leave a comment