What are they useful for?

Feb 5, 2014 at 9:53pm
http://en.cppreference.com/w/cpp/language/member_functions
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
struct S {
    void f() & { std::cout << "lvalue\n"; }
    void f() &&{ std::cout << "rvalue\n"; }
};
 
int main(){
    S s;
    s.f();            // prints "lvalue"
    std::move(s).f(); // prints "rvalue"
    S().f();          // prints "rvalue"
}
This is a cool feature I didn't know about, and I am curious of some practical/effective uses for it.
Feb 5, 2014 at 10:00pm
Isn't the reason for them explained in the paragraph immediately following prior to that code? You want the function to do one thing in the event that it is being called from\as an lvalue and something completely different for an rvalue.
Last edited on Feb 5, 2014 at 10:01pm
Feb 5, 2014 at 10:05pm
It's an optimization thing. If a function is potentially destructive to the object's state, you can overload the same function in 2 ways:

lvalue function: Will do the extra work to preserve the object's state

rvalue function: Can be faster and let the object's state fall to pieces, because it's a temp object anyway.


EDIT:

You want the function to do one thing in the event that it is being called from\as an lvalue and something completely different for an rvalue.


In general... that would be pretty horrible if your code actually did that. People would expect both versions of the function to behave the same (at least from a viewpoint external to the class).
Last edited on Feb 5, 2014 at 10:12pm
Feb 6, 2014 at 2:14am
Some people also like to lvalue ref qualify their copy-assignments and other operators that require lvalues in their built-in versions, to avoid the sort of silly code like std::string() = "abc"; that we put up with in C++98.

but yes, the real point is to trash this if you're the rvalue overload.
Feb 6, 2014 at 5:09am
Thanks, so it's a way to manually optimize the program :)
Feb 6, 2014 at 6:29am
> so it's a way to manually optimize the program

It could be used for manual optimization.
But its primary purpose, and most common use, is to allow class authors to enforce correct semantics.

This is the kind of code that people tend to routinely write
(return an expensive-to-copy object by reference to const):
1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <string>
#include <vector>

struct A
{
    const std::vector<std::string>& names() const { return names_ ; }

    std::vector<std::string> names_ ;
};

And it could be disastrous if A::names() is naively or carelessly called on an rvalue:
1
2
3
4
5
6
7
A foo() { return { { "one", "two", "three", "four", "five", "six" } } ; }

int main()
{
    for( const auto& s : foo().names() ) std::cout << s << ' ' ; // UB
    std::cout << '\n' ;
}

http://coliru.stacked-crooked.com/a/e5185f51151de5ed


With an overload for rvalues, the class author can enforce correct semantics.
(either return a copy by value, or disable the function altogether for rvalues):
http://coliru.stacked-crooked.com/a/6558e48bbabbecf1
Topic archived. No new replies allowed.