2

I have found the following snippet in a code implementing a list class

    void push_front( const T & x ) { insert( begin( ), x ); }

    void push_front( T && x ) { insert( begin( ), std::move( x ) );}

Now I know that if I have a function taking a parameter as an r-value, that parameter will be l-value in the scope of the function (Isn't that right?).

So I can replace the previous snippet by

void push_front( const T & x ) { insert( begin( ), x ); }

void push_front( T && x ) { push_front( x );}

The first question: Am I right?

The second one: By considering that the r-value parameter in the first snippet is an l-value parameter inside the second function, Will std::move( x ) cast x from l-value to r-value and the function push_front() call the r-value version of the function insert() or what?

An edit::

This is how insert() is implemented

    iterator insert( iterator itr, const T & x )
    {
        Node *p = itr.current;
        theSize++;
        return { p->prev = p->prev->next = new Node{ x, p->prev, p } };
    }


    iterator insert( iterator itr, T && x )
    {
        Node *p = itr.current;
        theSize++;
        return { p->prev = p->prev->next = new Node{ std::move( x ), p->prev, p } };
    }

The definition of Node

struct Node
    {
        private:
        T data;
        Node *prev;
        Node *next;

        Node( const T & d = T{ }, Node * p = nullptr,
        Node * n = nullptr )//It's possible because of const
        :data{ d }, prev{ p }, next{ n } { }

        Node( T && d, Node * p = nullptr, Node * n = nullptr )
        : data{ std::move( d ) }, prev{ p }, next{ n } { }
    };
asmmo
  • 6,922
  • 1
  • 11
  • 25
  • 1
    Your suggested replacement will copy the argument instead of moving from it as the first example does. Whether you are right to make the change depends on whether that is the behaviour you want ... – M.M Jan 27 '20 at 22:38
  • Almost everything you want to know can be found here: https://stackoverflow.com/questions/3106110/what-is-move-semantics – NathanOliver Jan 27 '20 at 22:39
  • @M.M I meant if `std::move(x)` converts x to `rvalue`, then `push_front(T&& )` will be called instead of `push_front(const T& )` – asmmo Jan 27 '20 at 22:44
  • @M.M If I have only two versions of `push_front()` (i.e) `push_front(T&& )` and `push_front(const T& )`, hence my object won't be copied and my replacement will be better, won't it? – asmmo Jan 27 '20 at 22:50
  • 1
    @anonymous your replacement would copy the object instead of moving it. The code `push_front( std::move(x) )` moves the object and `push_front(x)` does not – M.M Jan 28 '20 at 00:58

1 Answers1

1

I have a function taking a parameter as an r-value, that parameter will be l-value in the scope of the function

Yes. In general, all rvalue reference variables are lvalues, function parameters or not.

So I can replace the previous snippet by ...

Yes, but then push_front(T &&x) will copy x instead of moving it.

Will std::move( x ) cast x from l-value to r-value and the function push_front()call the r-value version of the function insert()

Yes.

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
  • 2
    Don't you mean you will copy instead of move for the second answer? – NathanOliver Jan 27 '20 at 22:42
  • If I have only two versions of push_front() (i.e) `push_front(T&& )` and `push_front(const T& )`, hence my object won't be copied and my replacement will be better, won't it? – asmmo Jan 27 '20 at 23:06
  • _In general, all rvalue references are lvalues, function parameters or not._ That's false. A call to a function returning rvalue reference is not an lvalue. – yuri kilochek Jan 27 '20 at 23:16
  • 1
    @anonymous `push_front(const T& )` copies the object. Since your `push_front(T&& )` uses `push_front(const T& )`, it will also copy. – HolyBlackCat Jan 27 '20 at 23:17
  • @yurikilochek I meant rvalue reference variables, edited to make it more clear. But technically the result of such a call is an rvalue of some non-reference type (not an rvalue reference). – HolyBlackCat Jan 27 '20 at 23:19
  • how does `push_front(const T& )` copy the object while it takes a constant reference to it – asmmo Jan 27 '20 at 23:20
  • @anonymous Merely passing the object to `push_front` doesn't copy it. Calling `insert( begin( ), x );` does. – HolyBlackCat Jan 27 '20 at 23:21
  • @HolyBlackCat `insert( begin( ), x )` function has only two versions `insert( it, T&& )` and `insert( it, const T& )` – asmmo Jan 27 '20 at 23:25
  • @anonymous Yes, the first one moves the object and the second one copies it. Your `push_front(const T& )` always calls the second one. – HolyBlackCat Jan 27 '20 at 23:26
  • @HolyBlackCat But what I know the first one moves the object and the second one takes a reference to it (the variable itself without any copying). Plz, more explanation about that. – asmmo Jan 27 '20 at 23:34
  • @anonymous Merely passing an object to it doesn't copy it (neither does merely passing something to `insert( it, T&& )` moves it). Copying/moving happens in the function body. (You didn't show how `insert` is implemented, so I can't know if it really copies/moves anything or not. But if the guy who wrote that code has some common sense, one of them moves the object and the other copies it.) – HolyBlackCat Jan 27 '20 at 23:38
  • I put the functions `insert()` of the class – asmmo Jan 27 '20 at 23:44
  • @anonymous Doing `new Node{ x, p->prev, p } ` copies `x`. – HolyBlackCat Jan 27 '20 at 23:45
  • It doesn't at ALL. Because it has two `ctor`s. one of them takes `r-value` and the other takes a constant ref. – asmmo Jan 27 '20 at 23:47
  • @anonymous Simply passing an object to a const reference doesn't copy it, yes. But I'm certain that the body of the constructor taking the const reference copies that reference. Add the definition of `class Node` to the question and we can check that. – HolyBlackCat Jan 27 '20 at 23:51
  • 1
    @anonymous Yeah, here's your copy: `:data{ d }`. – HolyBlackCat Jan 27 '20 at 23:54