Does the expression `new T` express rvalue or lvalue?

I am currently reading this tutorial / rvalue link explanation:

http://thbecker.net/articles/rvalue_references/section_07.html

In the second and last paragraph, the author mentions that "the argument of the copy constructor T in the factory body is lvalue." The code to which it refers is as follows:

template<typename T, typename Arg> shared_ptr<T> factory(Arg const & arg) { return shared_ptr<T>(new T(arg)); } 

I understand that new T(arg) building the T object on the heap, but it is not the return value of a temporary pointer that will be lost if it is not used (which will lead to a memory leak, I think) and therefore rvalue?

EDIT: just to clarify, I understand that there will be no memory leak in this example. I just meant that if the pointer value were not used, we would not have access to the constructed object T, and therefore we would get a memory leak.

+5
source share
4 answers

The short answer, I'm sure someone will write a longer one, but:

new gives you an rvalue pointer: new int = nullptr; unable to compile with error about the need for lvalue.

The dereferencing of this pointer gives you lvalue: *(new int) = 5; will compile (this naive statement is also a memory leak, because the pointer is lost, of course).

The copy constructor accepts the link, so if you have a pointer to an object, you need to dereference it.

If you lose the pointer, you cannot delete it, so it will not be destroyed and the heap memory will not be freed (until the program exits and the memory is returned to the OS).

If you place the pointer on some other object that can take it upon itself, for example, shared_ptr , then you will not lose the pointer. Another object will delete it in accordance with its semantics, at the latest when the other object (or the latter in case of sharing, for example, with shared_ptr ) itself destroys it.

+3
source

Many participants here seem confused by the fact that they are categories of values, some believe that shared_ptr "stores lvalue", which makes no sense.

Lvalue and rvalueness really have nothing to do with the fact that something "returns" or with the state of objects in memory; it's about the state of expressions in code. Is the expression lvalue or rvalue (or one of the others) from different language rules and constructs.

In short, lvalue expressions are names, and everything else is not an lvalue expression. One notable exception to this rule is *ptr , where ptr is a pointer type because *ptr is defined as the result of an lvalue for historical reasons (unless operator overloading is involved).

Now the standard does not explicitly propose that new β€œreturns” (evaluates) the value of rvalue, because this statement makes no sense. new evaluates a pointer to your new memory block, and according to the rules of the language, the expression new T is the value of rvalue, because it means what rvalue means.

It is difficult to explain it better without writing a book, but that is its essence.

I understand that the new T (arg) creates a T object on the heap, but it is not the return value of a temporary pointer that will be lost if it is not used (which will lead to a memory leak, which I assume), and therefore Rvalue?

Yes, essentially. The fact that this is a pointer to dynamically allocated memory is completely irrelevant.

+2
source

Returning new is the value of prvalue, not lvalue, because you cannot write:

  new T(arg) = ....; // not legal, so no lvalue 

The standard defines (Β§3.10): lvalue (so-called, historically, since lvalues ​​can appear on the left side of an assignment expression) denotes a function or object. And the return new denotes the address of the object, not the object itself.

If you assign this value to pointer a and look for that pointer, or even if you refer directly to the new return value, you will make it lvalue:

 *new T(arg) = ....; // valid, althoug you'd loose the address ! *a = ....; // normal poitner dereferencing 

This is explained in the standard (Β§5.3.1 / 1): The unary operator * performs an indirect call: the expression to which it is applied must be a pointer to an object type or a pointer to a function type and the result is an lvalue relating to the object or function, to which the expression refers.

Important: your editing and shared_ptr

Your example does not shared_ptr<T>(new T(arg)) : shared_ptr<T>(new T(arg)) creates a shared pointer that takes care of your newly created object and will delete it if it is no longer in use.

Two possibilities:

  • the reverse common pointer is used in the expression (for example, as a temporary common pointer or assigned to another shared_ptr object): the object is copied and its usage counts to reflect the number of live references to it, No leak!

  • an ignored reset common pointer is ignored: the returned object is destroyed, its usage score is reduced, and since it is not used elsewhere, your object is deleted.

+1
source

Unfortunately, the category of values ​​of operators and their operands is underspecified , which leaves us in an unsuccessful position to derive a category of values. Many believe that unless explicitly stated, the result is a prvalue.

We can make a rather educated guess by trying to use new on the left side of the destination and see that it does not work, and conclude that it does not give the value of lvalue, but we still remain in an undefined territory.

We can define it empirically, as this code from Luc Danton answers here :

 template<typename T> struct value_category { // Or can be an integral or enum value static constexpr auto value = "prvalue"; }; template<typename T> struct value_category<T&> { static constexpr auto value = "lvalue"; }; template<typename T> struct value_category<T&&> { static constexpr auto value = "xvalue"; }; // Double parens for ensuring we inspect an expression, // not an entity #define VALUE_CATEGORY(expr) value_category<decltype((expr))>::value 

and the result:

 std::cout << VALUE_CATEGORY( new int) << std::endl ; 

is an:

prvalue

which confirms our conclusion using the conclusion.

+1
source

Source: https://habr.com/ru/post/1203417/


All Articles