-1

Why would I std::move an std::shared_ptr?

Answers to this question point out that moving a std::shared_ptr is all about speed, but nobody explains why it is faster in detail. How expensive is it really in comparison? Is it worth optimzing when one uses it a lot?

ManuelSchneid3r
  • 15,850
  • 12
  • 65
  • 103
  • 1
    Its worth optimizing when profiling shows its an bottleneck in your application, otherwise its not. – tkausl Nov 21 '21 at 11:14
  • 3
    The accepted answer does explain why it's faster though? – UnholySheep Nov 21 '21 at 11:14
  • 2
    As the accepted answer (and comments) goes into detail about the cost of synchronising the counter of the shared pointer, could you change your question so it's not a duplicate ? – Richard Critten Nov 21 '21 at 11:18
  • @UnholySheep is it twice dozens hundreds faster? if its exactly 100 times faster as stated in this answer it would be nice to have some supporting data. – ManuelSchneid3r Nov 21 '21 at 11:28
  • There's no need to "profile". Just don't pessimize prematurely. If you are done with a shared_ptr, and you pass it somewhere, `std::move` it. Goes for any object, really. – StoryTeller - Unslander Monica Nov 21 '21 at 11:28
  • You *could* try posting a bounty on the original question to incentivize an answer that provides more detail. – EOF Nov 21 '21 at 11:30
  • 1
    A `shared_ptr` has two levels of indirection. One points at a data structure with an atomic counter. The next one points from there at the actual object. Moving a shared pointer involves a simple copy of the first pointer with nothing else to be done. The reference counter stays unchanged, because the number of `shared_ptr`s referencing it doesn’t change. Copying is much harder: Apart from copying a pointer, one must (also) atomically increment the reference counter in a thread-safe manner. An atomic instruction may take time equivalent to thousands of “non-atomic” instructions. – Andrej Podzimek Nov 21 '21 at 11:34

1 Answers1

1

I wrote a benchmark. On my Macbook Air it is three times faster (g++ as well as clang++ -std=c++17 -O3 -DNDEBUG). Let me know if you see problems with the benchmark.

#include <chrono>
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
using namespace std::chrono;


int COUNT = 50'000'000;

struct TimeIt
{
    system_clock::time_point start;
    TimeIt() {
        start = system_clock::now();
    }
    ~TimeIt() {
        auto runtime = duration_cast<milliseconds>(system_clock::now()-start).count();
        cout << runtime << " ms" << endl;
    }

};

void benchmark_copy(const vector<shared_ptr<int>> &vec_src)
{
    cout << "benchmark_copy" << endl;
    vector<shared_ptr<int>> vec_dst;
    vec_dst.reserve(COUNT);
    TimeIt ti;
    for(auto &sp : vec_src)
        vec_dst.emplace_back(sp);
}
void benchmark_move(vector<shared_ptr<int>> &&vec_src)
{
    cout << "benchmark_move" << endl;
    vector<shared_ptr<int>> vec_dst;
    vec_dst.reserve(COUNT);
    TimeIt ti;
    for(auto &sp : vec_src)
        vec_dst.emplace_back(move(sp));

}

int main (int arg, char **argv){

    vector<shared_ptr<int>> vec;
    for (int i = 0; i < COUNT; ++i)
        vec.emplace_back(new int);

    benchmark_copy(vec);
    benchmark_move(move(vec));

}
ManuelSchneid3r
  • 15,850
  • 12
  • 65
  • 103