1

I have a method

structA { shared_ptr<B> m_b; // 2 options to set m_b void setB1(shared_ptr<B> b) { m_b = move(b); } void setB2(shared_ptr<B> const&b) { m_b = b; } }; 

Which one is better in performance? They both do copies if I call setB1 as setB1(b) other than setB1(move(b)). I am more concerned about its performance when b can be nullified and b can only be copied.

My Testing Answers on VC2015:

setB1 is faster than setB2

  • by 30% for lvalue b
  • by 8% for rvalue b
4
  • 3
    Presumably you intended for the type of m_b to be shared_ptr<B> and not just B. Commented Jul 16, 2016 at 15:30
  • 2
    These two do different things: copy creates new shared_ptr pointing to the same thing, moving nullifies original shared_ptr. Rather than about performance, you should think about what your goal is. Commented Jul 16, 2016 at 15:43
  • @GingerPlusPlus : Moving nullifies the local b object which is destroyed upon function exit anyway. Commented Jul 16, 2016 at 15:47
  • @GingerPlusPlus They both do copies if I call setB1 as setB1(b) other than setB1(move(b)). I am more concerned about its performance, for example when b can be nullified. Commented Jul 16, 2016 at 16:28

2 Answers 2

0

The difference in performance is going to be tiny here.

One of them creates a copy into the argument, then moves out of it.

The other refers to an external copy in the argument, and copies out of it.

If you call the first with a shared ptr creating function (like make_shared), you'll get 1 move and 0 copies and 1 trivial destroy. For the second, you get 0 moves and 1 copy and 1 non-trivial destroy.

If you call the first just passing in some random shared ptr by value, you get 1 copy and 1 move and 1 trivial destroy. In the second, you get 1 copy and 0 moves.

Copying a shared ptr is an atomic increment. Trivial destroy is a branch. Non-trivial is a branch and an atomic decrement. Moving a shared ptr is just setting some pointers.

Sign up to request clarification or add additional context in comments.

2 Comments

The reason I downvoted is the unsupported assertion that "The difference in performance is going to be tiny". I've seen that shared_ptr can add significant overhead in some cases, mostly because copying the shared_ptr causes atomic operations that can hit both single and multi-thread performance. OP' small perf test reflects that. Moving the shared_ptr is clearly preferable when possible.
@aber I ipvoted yours for the same reason. Except unless you probably shouldn't normally be using shared ptr if almost every use is a creation use. ;)
0

The answer is Yes, and setB1 is generally better.

  • Copying a shared-pointer makes expensive (slow) atomic increment/decrement operations on the reference count.

  • Moving a shared-pointer is almost free and is basically just copying a pointer non-atomically (could be a single assembly instruction).

In your sample, setB1 provides the user the choice to either move or copy the shared_ptr, allowing for optimal performance when a move is possible for the user, while setB2 forces a copy.

See a detailed explanation for the performance difference here: Why would I std::move an std::shared_ptr?

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.