3

I've seen quite a lot of code in my company where functions take rvalue arguments.

Example:

void Notifier::PostEvent(std::unique_ptr<IEvent>&& event)
{
    std::unique_lock<std::mutex> lock(m_Mutex);
    m_events.push_back(std::move(event));
    m_conditionVariable.notify_all();
}

There are no templates here. This could easily have written like this:

void Notifier::PostEvent(std::unique_ptr<IEvent> event)
{
    std::unique_lock<std::mutex> lock(m_Mutex);
    m_events.push_back(std::move(event));
    m_conditionVariable.notify_all();
}

Since the parameter 'event' is a sink value in both cases they are effectively the same. I think the only advantage with the first version is that it saves one move constructor for the unique_ptr. Is that correct? Is it really worth it?

jignatius
  • 5,606
  • 2
  • 7
  • 21
  • 4
    Possible duplicate of [Pass by value vs pass by rvalue reference](https://stackoverflow.com/questions/37935393/pass-by-value-vs-pass-by-rvalue-reference) – Evg Jun 22 '19 at 11:45
  • 1
    Possible duplicate of [How do I pass a unique\_ptr argument to a constructor or a function?](https://stackoverflow.com/questions/8114276/how-do-i-pass-a-unique-ptr-argument-to-a-constructor-or-a-function) – Richard Critten Jun 22 '19 at 12:34

1 Answers1

3

Ok. Now I understand better after reading How do I pass a unique_ptr argument to a constructor or a function?

What's happening is that in my first example, where I am passing by rvalue reference, it's more or less similar to passing by non-const lvalue reference. Although you might expect the parameter to be empty after the function call there is no guarantee. It all depends on what the function actually does with it. By pushing/moving it into a vector like what I am doing here the unique_ptr will be empty. However, if I don't do any moving (say I just call a method of the IEvent class) then the unique_ptr is not empty.

The unique_ptr rvalue reference parameter, therefore, actually does not guarantee what happens to the value after the call, i.e. whether it is a sink or not. It could be empty after the call or it may not be. Only by inspecting the code can you determine what will happen.

I think in retrospect the second function definition where it takes a unique_ptr by value is better. That ensures that the unique_ptr has been moved and should no longer be used afterward.

jignatius
  • 5,606
  • 2
  • 7
  • 21