1

I have a code which have to deal with rvalued stl containers. My question is: why member functions which return an element from rvalued-stl-container, like in:

vector<int>{1}.front()

returns lvalue and not rvalue? Standard specifies that member of rvalue object is rvalue. I know that I can explicitly move returned element with std::move. But what is a logic of having lvalue return type when returned value is clearly rvalue?

If you would use such an expression as an argument of some valuness-overloaded function, wrong overload will be selected and called function would get a lvalue reference (soon to become dangling).

ildjarn
  • 62,044
  • 9
  • 127
  • 211
Leonid Volnitsky
  • 8,854
  • 5
  • 38
  • 53
  • 2
    Simply because there are no rvalue overloads for the memberfunctions, like `T&& front() &&{ return move(front()); }` – Xeo Feb 01 '13 at 09:56
  • So, than this is STD defect waiting for rvalue-for-this feature to be implemented? – Leonid Volnitsky Feb 01 '13 at 10:02
  • I dunno if this really counts as a defect in the standard, but you may aswell try a report in the http://isocpp.org mailing lists. – Xeo Feb 01 '13 at 10:05

2 Answers2

1

Maybe the addition of outplace_front() and outplace_back() for outbound rvalues would be better names in the spirit of emplace_front() and emplace_back() for inbound rvalues.

TemplateRex
  • 69,038
  • 19
  • 164
  • 304
  • 1
    Huh? `front() &&` would `move` the element, it wouldn't remove it. – ecatmur Feb 01 '13 at 10:21
  • @ecatmur and the element count of vector would have to be decreased, right? – TemplateRex Feb 01 '13 at 10:22
  • @DeadMG what semantics would outbound rvalue moves have on containers? – TemplateRex Feb 01 '13 at 10:23
  • @rhalbersma - element can be moved out from container, but it does not have to be removed from it. It just have to be left in destructible state. – Leonid Volnitsky Feb 01 '13 at 10:28
  • @LeonidVolnitsky how would that not break a container's invariants? an iterator pointing to a moved out element can no longer be safely derefenced. – TemplateRex Feb 01 '13 at 10:37
  • You won't be able to use rvalued container after next sequence point - it will be destructed. – Leonid Volnitsky Feb 01 '13 at 10:42
  • 1
    @rhalbersma sure it can; the moved out element is in an *unspecified but valid state*. – ecatmur Feb 01 '13 at 10:43
  • @ecatmur OK, I realize that now, but still, it is extremely confusing and that behavior should be made explicit through named functions, not through an overload. – TemplateRex Feb 01 '13 at 10:53
  • It might seem a little odd, but since the container is an xvalue you're hardly likely to be able to observe what happened to the original element anyway, unless you're doing some pretty hairy stuff. – ecatmur Feb 01 '13 at 11:01
  • @rhalbersma I realize, I should rather bookmark this http://stackoverflow.com/q/7027523/743214 ;) – Christian Rau Feb 01 '13 at 11:54
  • This wouldn't add much, since `c.outplace_front()` is equivalent to `std::move(c.front())`. And it's not actually a counterpart to `emplace_front`, which constructs the element from scratch. – aschepler Feb 07 '13 at 00:08
1

Once the compiler has decided to call a particular member function (int &std::vector<int>::front(), say) the type system only knows that an int & is returned, so it has to treat that as an lvalue even though its lifetime is limited to that of the owner temporary.

Before C++11 it was not possible for a member function to be overloaded according to the value category of the object it is being called on (see What is "rvalue reference for *this"?), only on cv-qualification of the object; and a non-const temporary is clearly not const so the non-const overloads must be available.

As well as the potentially dangling lvalue references you've identified, this led in C++03 to the situation where operator<< on a temporary ostream could be called with a char (member function operator) but not with a string (free operator); C++11 fixes this with free operator overloads for rvalue references and rvalue *this overload for member functions.

Rvalue *this allows three overloads for front:

T &front() & { return data_[0]; }
const T &front() const & { return data_[0]; }
T &&front() && { return std::move(data_[0]); }

The different function body for the rvalue overload is a bit of a wart; this is because the ref-qualifier has no effect on member of *this access within the body of a member function.

Community
  • 1
  • 1
ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • That proposal was accepted and is a part of C++11. Clang supports it now, most of the other compilers do not. – Puppy Feb 01 '13 at 10:21