Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is its lifetime of a return value extended to the scope of the calling function when it is bound to a const reference in the calling function?

"If you return a value (not a reference) from the function, then bind it to a const reference in the calling function, its lifetime would be extended to the scope of the calling function."

So: CASE A

const BoundingBox Player::GetBoundingBox(void)
{
    return BoundingBox( &GetBoundingSphere() );
}

Returns a value of type const BoundingBox from function GetBoundingBox()

variant I: (Bind it to a const reference)

const BoundingBox& l_Bbox = l_pPlayer->GetBoundingBox();

variant II: (Bind it to a const copy)

const BoundingBox l_Bbox = l_pPlayer->GetBoundingBox();

Both work fine and I don't see the l_Bbox object going out of scope. (Though, I understand in variant one, the copy constructor is not called and thus is slightly better than variant II).

Also, for comparison, I made the following changes.

CASE B

BoundingBox Player::GetBoundingBox(void)
{
    return BoundingBox( &GetBoundingSphere() );
}

with Variants: I

BoundingBox& l_Bbox = l_pPlayer->GetBoundingBox();

and II:

BoundingBox l_Bbox = l_pPlayer->GetBoundingBox();

The object l_Bbox still does not go out scope. How does "bind it to a const reference in the calling function, its lifetime would be extended to the scope of the calling function", really extend the lifetime of the object to the scope of the calling function ?

Am I missing something trivial here?

like image 729
brainydexter Avatar asked Apr 10 '10 21:04

brainydexter


2 Answers

Normally a temporary object (such as one returned by a function call) has a lifetime that extends to the end of the "enclosing expression". However, a temporary bound to a reference generally has it's lifetime 'promoted' to the lifetime of the reference (which may or may not be the lifetime of the calling function), but there are a couple exceptions. This is covered by the standard in 12.2/5 "Temporary objects":

The temporary to which the reference is bound or the temporary that is the complete object to a subobject of which the temporary is bound persists for the lifetime of the reference except as specified below. A temporary bound to a reference member in a constructor’s ctor-initializer (12.6.2) persists until the constructor exits. 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.

See the following for more information:

  • C++ constant reference lifetime (container adaptor)
  • GotW #88: A Candidate For the "Most Important const"

An example that might help visualize what's going on:

#include <iostream>
#include <string>

class foo {
public:
    foo( std::string const& n) : name(n) { 
        std::cout << "foo ctor - " << name + " created\n"; 
    };
    foo( foo const& other) : name( other.name + " copy") { 
        std::cout << "foo copy ctor - " << name + " created\n";
    };

    ~foo() { 
        std::cout << name + " destroyed\n"; 
    };

    std::string getname() const { return name; };
    foo getcopy() const { return foo( *this); };

private:
    std::string name;
};

std::ostream& operator<<( std::ostream& strm, foo const& f) {
    strm << f.getname();
    return strm;
}


int main()
{
    foo x( "x");

    std::cout << x.getcopy() << std::endl;

    std::cout << "note that the temp has already been destroyed\n\n\n";

    foo const& ref( x.getcopy());

    std::cout << ref << std::endl;

    std::cout << "the temp won't be deleted until after this...\n\n";
    std::cout << "note that the temp has *not* been destroyed yet...\n\n";
}

Which displays:

foo ctor - x created
foo copy ctor - x copy created
x copy
x copy destroyed
note that the temp has already been destroyed


foo copy ctor - x copy created
x copy
the temp won't be deleted until after this...

note that the temp has *not* been destroyed yet...

x copy destroyed
x destroyed
like image 85
Michael Burr Avatar answered Oct 13 '22 20:10

Michael Burr


Firstly, the lifetime of temporary object gets extended to the lifetime of const reference that's bound to it, not "to the scope of the calling function" (although maybe that what you meant by that strange wording "the scope of the calling function"). This is what your CASE A illustrates, where you attach a const reference to a temporary. The temporary continues to live as long as the reference lives. When the reference ends its lifetime, the temporary object gets destroyed as well.

Secondly, your CASE B is simply ill-formed, non-compilable. Namely, the

BoundingBox& l_Bbox = l_pPlayer->GetBoundingBox(); 

is illegal. It is illegal in C++ to attach a non-const reference to a temporary. If your compiler allows it, it must be a quirk/extension of your compiler, which has little to do with C++ language.

like image 26
AnT Avatar answered Oct 13 '22 19:10

AnT