0

I was reading a good tutorial on lvalue/rvalue references. If I've understood correctly when there is type deduction something like T&& can accept both an lvalue and an rvalue.

But is there a way to achieve that without a generic class? I'd like to avoid duplicating all my methods for accepting both lvalues and rvalues. And of course avoid passing big objects by value.

Shepard
  • 801
  • 3
  • 9
  • 17

2 Answers2

2

r-value references are mostly use in move-constructor and move assignment.

For regular method, you may stick with one reference type only:

  • For read only parameter (without copy), const reference is enough.

  • if you have to do a copy, you may take your argument by value and use std::move:

Example:

class Test
{
public:

    void displayString(const std::string& s) const { std::cout << s << m_s; }

    void setString(std::string s) { m_s = std::move(s); }

private:
    std::string m_s;
};
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • What does `std::move` does exactly? Does it copy directly the parameter inside `m_s` instead of `s`? – Shepard Jan 01 '15 at 02:11
  • `std::move` perform a cast to r-value. `std::string` provides move-assign which will *steal* the resource from `s`. – Jarod42 Jan 01 '15 at 02:13
  • So the target class (in my case glm::vec3) must support the move semantics in order to do it, right? – Shepard Jan 01 '15 at 02:18
  • 1
    The target class must provide a move-assignment/move constructor. – Jarod42 Jan 01 '15 at 02:20
  • Thank you!! One last question: what is the advantage of moving data? I mean, at compiler level. It seems to me that data has to be copied only once (directly in m_s) instead of twice (first on the stack of `setString` then in m_s) but this is entirely my idea. Is it something like this? – Shepard Jan 01 '15 at 02:29
  • @Shepard: Move constructor/assignment may just work with pointer directly instead of doing deep copy. – Jarod42 Jan 01 '15 at 09:37
1

If the function that you implement does not need rvalue semantic, then you can simply pass the argument by reference or by constant reference.

However, if you can take advantage of rvalues and do not want to duplicate your code, you can pass by value and move the result. That should be almost as efficient and can be more maintainable than code duplication or an implementation with universal references.

This answer shows the technique: Should all/most setter functions in C++11 be written as function templates accepting universal references?

// copy, then move
void set_a(A a_) { a = std::move(a_); }
Community
  • 1
  • 1
Philipp Claßen
  • 41,306
  • 31
  • 146
  • 239
  • 3
    *"That should be almost as efficient and can be more maintainable."* This depends on the use case. [Herb Sutter argues](http://youtu.be/xnqTKD8uD64?t=51m8s) that for setter-like functions, pass-by-const-ref is a reasonable default (still in C++14), with the option of adding a pass-by-rvalue-ref later. – dyp Jan 01 '15 at 02:03
  • @dyp Right, I clarified that I meant "more maintainable than universal references or code duplication". If you can just avoid it, and a simple const-ref is good enough, then I agree completely with your argument. – Philipp Claßen Jan 01 '15 at 02:17
  • I don't quite understand what you're referring to with "more maintainable than [..] an implementation using universal references". What makes such a solution less maintainable? – dyp Jan 01 '15 at 02:18
  • @dyp The type checking of universal references is less strict. That can sometimes be an advantage but it can also be an disadvantage. The copy+move implementation is less tricky. – Philipp Claßen Jan 01 '15 at 02:20