c++pass-by-valueforwarding-referencepass-by-const-referencepass-by-rvalue-reference

Pass-by-value and std::move vs forwarding reference


I encounter the pass by value and move idiom quite often:

struct Test
{
    Test(std::string str_) : str{std::move(str_)} {}
    std::string str;
};

But it seems to me that passing by either const reference or rvalue reference can save a copy in some situations. Something like:

struct Test1
{
    Test1(std::string&& str_) : str{std::move(str_)} {}
    Test1(std::string const& str_) : str{str_} {}
    std::string str;
};

Or maybe using a forwarding reference to avoid writing both constructors. Something like:

struct Test2
{
    template<typename T> Test2(T&& str_) : str{std::forward<T>(str_)} {}
    std::string str;
};

Is this the case? And if so, why is it not used instead?

Additionally, it looks like C++20 allows the use of auto parameters to simplify the syntax. I am not sure what the syntax would be in this case. Consider:

struct Test3
{
    Test3(auto&& str_) : str{std::forward<decltype(str_)>(str_)} {}
    std::string str;
};

struct Test4
{
    Test4(auto str_) : str{std::forward<decltype(str_)>(str_)} {}
    std::string str;
};

Edit:

The suggested questions are informative, but they do not mention the "auto" case.


Solution

  • But it seems to me that passing by either const reference or rvalue reference can save a copy in some situations.

    Indeed, but it requires more overloads (and even worst with several parameters).

    Pass by value and move idiom has (at worst) one extra move. which is a good trade-off most of the time.

    maybe using a forwarding reference to avoid writing both constructors.

    Forwarding reference has its own pitfalls: