Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extending the lifetime of a temporary object by binding to its subobject

In C++ documentation it is said that if a reference is bound to a subobject of a temporary object then the lifetime of the temporary object is extended where the subobject is denoted by a temporary materialization conversion.

#include <iostream>

struct Data {
  Data(int v = 0) : val(v) {
    std::cout << "Data(" << val << ")" << std::endl;
  }

  ~Data() {
    std::cout << "~Data(" << val << ")" << std::endl;
  }

  int val;
};

struct Type {
  Data value;

  Type(int v = 99) : value(v) {
    std::cout << "Type()" << std::endl;
  }

  ~Type() {
    std::cout << "~Type()" << std::endl;
  }

  Data& data() && {
    return value;
  }
};

Type MakeType() {
  return Type();
}

int main() {
  // 1. 
  const Data& d1 = MakeType().data();
  std::cout << "data is " << d1.val << std::endl;  

  // 2. 
  const Data& d2 = MakeType().value;
  std::cout << "data is " << d2.val << std::endl;

  return 0;
}

Documentation said that temporary materialization occurs in the following situations:

when accessing a non-static data member of a class prvalue; when invoking an implicit object member function of a class prvalue;

So, why is the life of the temporary object not extended in the first case but extended in the second case?

I read that a reference is just an alternative name for an object, so it denotes the object, but I can't use it like in the second case.

Is a different value category for expressions MakeType().data() and MakeType().value a reason?

Thanks.

like image 580
l17dev Avatar asked Oct 19 '25 19:10

l17dev


1 Answers

MakeType().value is accessing a non-static data member (NSDM) of a prvalue. MakeType() results in a prvalue, and .value names an NSDM of the object to the left. By the rules of C++, this must access an NSDM of a prvalue.

MakeType().data() is calling a member function of a prvalue. .data() is a member function call, so that's what this does.

Now, the result of that function call just so happens to be a reference to an object that just so happens to be an NSDM of something that was a prvalue (it stopped being a prvalue when you called a member function on it, but that doesn't really matter). But, the C++ standard doesn't care about happenstance; as far as the language is concerned, this is just a function call. It cannot know what's going on inside that function, so the inside of that function cannot affect the meaning of the expression that invoked it.

like image 199
Nicol Bolas Avatar answered Oct 22 '25 10:10

Nicol Bolas



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!