1

I read a lot of information about rvalue links, I understood everything, but I met this example:

template<class T, class Arg>
T* make_raw_ptr(Arg &&arg)
{
    return new T(arg);
}; 

If you pass rvalue to the make_raw_ptr function without using the my_forward function, when using new T, there will be a copy constructor, not a move constructor. I understand that arg will be lvalue, despite the fact that it is an rvalue reference, but I have one question. Why make a static_cast arg to an rvalue link when it is already an rvalue link, while using a static_cast<A&&> to arg, the move constructor will be called?

康桓瑋
  • 33,481
  • 5
  • 40
  • 90
malloc
  • 81
  • 6
  • That's not an "rvalue link" ; it's a *forwarding* reference because it is in a deduced context. I think you'll find [this page](https://en.cppreference.com/w/cpp/language/reference) highly informative. – WhozCraig May 13 '22 at 04:53
  • I think I figure it out... Rvalue reference is lvalue because it is reference and we can imagine it as "const Arg &arg = rvalue", but without const ofc. In this case, there is copy constuctor will be called, not move. Am I right? @WhozCraig – malloc May 13 '22 at 05:48
  • @malloc this is just a mental model, but in general: if it is has a name, it's an lvalue, unless explicitly cast to rvalue. As for the example you gave, `arg` is neither lvalue nor rvalue reference, it's a forwarding reference which is deduced at compile time to either r- or l- value one. – alagner May 13 '22 at 06:04
  • @alagner why isn't arg lvalue? [Here](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html) is said "An rvalue reference behaves just like an lvalue reference except that it can bind to a temporary". It explains why copy constructor will be called in my example. – malloc May 13 '22 at 06:16
  • @malloc it's been answered already: it's a template argument deduced at compile time, so it's a [forwarding reference](https://stackoverflow.com/questions/45996187/c-forwarding-reference-and-r-value-reference) (from caller's perspective). Inside the function `make_raw_ptr` it generally is an lvalue as (to put it simply) it has a name. See [this](https://stackoverflow.com/a/58761212/4885321) for more info. – alagner May 13 '22 at 06:28

1 Answers1

3

arg itself is an expression that represents an object referred to by arg and its value category is lvalue. It doesn't matter what the type of arg actually is. A name of a variable / function parameter itself is always an lvalue expression.

static_cast<A&&>(arg) is an expression that represents the very same object as arg, but its category is rvalue (and xvalue). When you use this expression as the constructor argument, the move constructor will be preferred. The same effect is with std::move(arg).

Daniel Langr
  • 22,196
  • 3
  • 50
  • 93