Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
108 views
in Technique[技术] by (71.8m points)

c++ - Passing by value vs const & and && overloads

So after looking up move semantics I see that general consensus is to pass by value when you intend to transfer ownership. But in Scott Meyer's talk on Universal references I've noticed that std::vector::push_back has 2 overloads:

void push_back( const T& value );
void push_back( T&& value );

So I thought to myself, wouldn't void push_back( T value ); be enough? I've asked a few people which ultimately lead to the following test case:

#include <memory>
#include <iostream>
#include <type_traits>

struct A
{
    A() { std::cout << "A Default constructor
"; }
    A(const A &) { std::cout << "A Copy
"; }
    A(A &&) { std::cout << "A Move
"; }
};

std::aligned_storage<sizeof(A)> contents;
A& alias = *reinterpret_cast<A*>(&contents);

void ByVal(A a)
{
    new (&contents) A(std::move(a));
    alias.~A();
}

void ByLCRef(A const& a)
{
    new (&contents) A(a);
    alias.~A();
}

void ByRRef(A&& a)
{
    new (&contents) A(std::move(a));
    alias.~A();
}

int main()
{
    A a;
    std::cout << "
";
    std::cout << "ByVal(a);
";
    ByVal(a);
    std::cout << "ByVal(std::move(a));
";
    ByVal(std::move(a));
    std::cout << "ByVal(A());
";
    ByVal(A());
    std::cout << "ByLCRef(a);
";
    ByLCRef(a);
    std::cout << "ByRRef(std::move(a));
";
    ByRRef(std::move(a));
    std::cout << "ByRRef(A());
";
    ByRRef(A());
}

Which produces the following:

A Default constructor

ByVal(a);
A Copy
A Move
ByVal(std::move(a));
A Move
A Move
ByVal(A());
A Default constructor
A Move
ByLCRef(a);
A Copy
ByRRef(std::move(a));
A Move
ByRRef(A());
A Default constructor
A Move

As you can see, ByVal produces 1 extra move compared to pair of reference overloads. So the question is: is it worth it? When would you create two overloads instead of one simple pass by value function?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

As you can see, ByVal produces 1 extra move compared to pair of reference overloads. So the question is: is it worth it? When would you create two overloads instead of one simple pass by value function?

+1 Most people who ask this question don't bother to do the analysis. So you get my upvote for doing your own homework. :-)

Whether it is worth it or not is going to depend on the cost of the move constructor, and on how many arguments the function takes. On one extreme, if the move constructor isn't that fast, you may care a lot about eliminating them (favoring the const&, && overload solution). At the other extreme, if your function has 4 parameters, each of which need lvalue/rvalue treatment, you may not be willing to write 16 overloads to cover all the cases. That's a lot of code to maintain, and the inherent code complexity is an invitation for bugs. So the by-value approach looks more attractive (which requires no overloads).

So imho, there is no general answer to the "is it worth it" question. The best answer is to equip yourself with the knowledge about the cost of each solution, as you have already done, and make an engineering judgement on a case by case basis.

Update

In the case of vector<T>::push_back imho the const&, && overload solution is worth it. There is only one parameter, and we have no idea how expensive the move constructor is. Indeed, we don't even know if there is a move constructor. Modifying your experiment to test out that latter case (removing the move constructor):

ByVal(a);
A Copy
A Copy

ByLCRef(a);
A Copy

Do you want to pay one copy or two to copy your A into the vector?

I.e. the less you know about your parameters, the more you have to lean towards the performance side, especially if you're writing something as heavily used as std::vector.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...