Search code examples
c++c++11rvalue-reference

C++ - Functions calling setters - how to decorate the arguments?


It is my understanding that the current (post-C++11) convention is to write setters with movable types as follows:

void set_a(A a) {
    a_ = std::move(a);
}

What is the best way to write another setter or forwarder function that calls this set_a()? For example:

void set_ab(A a, B b) {
    set_a(std::move(a));  // like this?
    set_b(b);  // or like this?
}

Or:

void do_one(A a) {  // by value? by const ref? by rvalue-ref?
    do_two(a);  // move?
}
void do_two(A a) {
   obj.set_a(a);
}

I don't think std::move() is appropriate here, so how should I write this for efficiency, assuming an optimizing compiler?

Do all these function signatures depend on whether I'm storing the final A object somewhere or not?

Thanks


Solution

  • When you have a value you are not going to reuse, std::move it.

    When you have an rvalue reference you are not going to reuse, std::move it.

    When a forwarding reference, std::forward it if and only if you'd move it if it was an rvalue reference.

    The rule to take by value presumes:

    1. You don't mind silently making a copy at the call site

    2. Moving is so cheap you treat it as free

    3. Copying is much more expensive than moving

    If (1) is false, instead take an rvalue reference (A&&) in your sink parameter. Now callers have to explicitly make their copy.

    If (2) is false, perfect forwarding, multiple overloads, type-erased emplacing, or a myriad of other more complex solutions should be used.

    If (3) is false, don't bother with moveing. Just take by value.

    If all 3 are true, then your set_ab looks like:

    void set_ab(A a, B b) {
      set_a(std::move(a));
      set_b(std::move(b));
    }