Home > Net >  Can a reference prolong the lifetime of any member data of a class which is returned by a mamber fun
Can a reference prolong the lifetime of any member data of a class which is returned by a mamber fun

Time:03-09

class sample
{
  std::string mString;

public:
  void Set(const std::string &s)
  {
    mString = s;
  }

  //std::string Get() const
  const std::string& Get() const
  {
    return mString;
  }
};

Let's say I have such a class as above and now I use this class like this:

sample *p = new sample;
p->Set("abcdefg");
const std::string& ref = p->Get();
delete p;
p = nullptr;
std::cout << ref << std::endl;

As you see, the member function Get returns a reference, which is assigned to the outer reference ref. After that, the whole object is deleted.

However, it seems that this code works without any error.

I'm a little confused. It could run just because I'm lucky or it's the reference ref that prolongs the lifetime of the member variable mString?

CodePudding user response:

No, lifetime extension by reference binding applies only to temporary objects materialized from prvalues.

Objects created with new never have their lifetime extended past delete.

What you are seeing here is just a manifestation of undefined behavior. ref is dangling after delete p; and therefore reading from it in the cout statement has undefined behavior.


If Get was returning by-value (std::string Get() const), then it would be true that the temporary materialized from the return value of the function would have its lifetime extended to that of the reference ref.

And in that case the program behavior would be well-defined.


Similarly if the sample object had automatic storage duration, the reference would not extent its lifetime or the lifetime of one of its subobjects either:

/* DO NOT USE: Undefined behavior */

const std::string& ref = []() -> const std::string& {
    sample s;
    p.Set("abcdefg");
    return s->Get();
    // lifetime of s ends with function returning
}();

/* UNDEFINED BEHAVIOR */    
std::cout << ref << std::endl;

Here it is the lambda's return type that would need to be changed from const std::string& to std::string to avoid the UB. Only the first reference binding can extent lifetime and therefore changing the return type of Get would not be sufficient in this case.

  • Related