Const reference VS move semantics

后端 未结 1 877
北海茫月
北海茫月 2020-12-04 13:23

I was wondering in which situations I still need to use const references in parameters since C++11. I don\'t fully understand move semantics but I think this is a legit ques

相关标签:
1条回答
  • 2020-12-04 13:56

    The solution you propose:

    void add(T value) {
         _impl.push_back(value);
    }
    

    Would require some adjustment, since this way you do always end up performing one copy of value, even if you pass an rvalue to add() (two copies if you pass an lvalue): since value is an lvalue, the compiler won't automatically move from it when you pass it as an argument to push_back.

    Instead, you should do this:

    void add(T value) {
         _impl.push_back(std::move(value));
    //                   ^^^^^^^^^
    }
    

    This is better, but still not sufficiently good for template code, because you do not know if T is cheap or expensive to move. If T is a POD like this:

    struct X
    {
        double x;
        int i;
        char arr[255];
    };
    

    Then moving it won't be any faster than copying it (in fact, moving it would be the same thing as copying it). Because your generic code is supposed to avoid unnecessary operations (and that's because those operations may be expensive for some types), you cannot afford taking the parameter by value.

    One possible solution (the one adopted by the C++ standard library) is to provide two overloads of add(), one taking an lvalue reference and one taking an rvalue reference:

    void add(T const& val) { _impl.push_back(val); }
    void add(T&& val) { _impl.push_back(std::move(val)); }
    

    Another possibility is to provide a (possibly SFINAE-constrained) perfect-forwarding template version of add() that would accept a so-called universal reference (non-standard term coined by Scott Meyers):

    template<typename U>
    void add(U&& val) { _impl.push_back(std::forward<U>(val)); }
    

    Both these solutions are optimal in the sense that only one copy is performed when lvalues are provided, and only one move is performed when rvalues are provided.

    0 讨论(0)
提交回复
热议问题