4

In a function like:

template<class Iterator>
A simple_return(Iterator it)
{
    return *it;
}

A a = simple_return(my_it); 

The compiler can easily perform a RVO, so do that:

template<class Iterator>
A simple_return(Iterator it)
{
    A tmp = *it;
    return tmp;
}

However, I have seen the second way is sometimes preferable over the former, for example in STL algorithm implementations (gcc), and I want to know if that affects RVO in any way (as std::move(*it) or std::move(tmp) does), or has any other reason, for example, regarding conversions or anything else.

For example, reserver_iterator, instead of:

reference operator*() const
{
     return *--Iterator(current);
}

uses:

reference operator*() const
{
     Iterator tmp = current;
     return *--tmp;
}

I ask that because, for implementing overloadings like operator+, I use extensively the pattern:

friend A operator+(const A& a, const A& b)
{ return A(a) += b; }

instead of:

friend A operator+(const A& a, const A& b)
{
    A tmp(a);
    return tmp += b;
}

Which isn't specially more readable but makes it be 3 lines longer (this two sentences in one line would be ugly).

ABu
  • 10,423
  • 6
  • 52
  • 103

1 Answers1

1

Due to named return value optimisation (NRVO), both variants of simple_return should produce the exact same machine code. And they do, even with conversions. As a result, there shouldn't be any practical difference between the two.

As mentioned by @cpplearner, it is done in your STL example because prefix decrement cannot be used on rvalues (e.g. if Iterator is a pointer). This may be the case in other parts.

ralismark
  • 746
  • 9
  • 24
  • The reason has already been pointed out in a comment on the question. –  Apr 23 '17 at 12:04
  • @hvd, changed the answer to mention that. – ralismark Apr 23 '17 at 12:11
  • The comment was correct, but I don't think your answer is. For plenty of rvalues, the prefix decrement operator can be used. For pointers it can't, but when you're dealing with iterators implemented as classes, `Iterator(current)` is still an rvalue. It's just that on *that* rvalue, prefix decrement may be supported as well. –  Apr 23 '17 at 12:30
  • Primitive types hasn't `this` pointers. So, modifiers operators requires lvalues, to modify the object and not the value. However, temporaries of class types, although there are rvalues, have `this` pointers, and you can called any function member through rvalues of class type. I don't know how all of it is translated in Standard terms, but the reason `operator--()` works with rvalues except pointers must be related with this. – ABu Apr 23 '17 at 16:31