为什么我要 std::move 一个 std::shared_ptr?

新手上路,请多包涵

我一直在查看 Clang 源代码,发现了这个片段:

 void CompilerInstance::setInvocation(
    std::shared_ptr<CompilerInvocation> Value) {
  Invocation = std::move(Value);
}

为什么我要 std::move 一个 std::shared_ptr

转移共享资源的所有权有什么意义吗?

我为什么不这样做呢?

 void CompilerInstance::setInvocation(
    std::shared_ptr<CompilerInvocation> Value) {
  Invocation = Value;
}

原文由 sdgfsdh 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.6k
2 个回答

我认为其他答案没有足够强调的一件事是 _速度_。

std::shared_ptr 引用计数是 原子 的。增加或减少引用计数 需要 原子 增量或减量。这比 非原子 递增/递减 了一百倍,更不用说如果我们递增和递减同一个计数器,我们最终会得到确切的数字,在这个过程中浪费了大量的时间和资源。

通过移动 shared_ptr 而不是复制它,我们“窃取”了 原子 引用计数,并使另一个 shared_ptr 无效。 “窃取”引用计数不是 原子 的,它比复制 shared_ptr 快一百倍(并导致 原子 引用递增或递减)。

请注意,此技术纯粹用于优化。复制它(如您所建议的)在功能方面同样出色。

原文由 David Haim 发布,翻译遵循 CC BY-SA 4.0 许可协议

不幸的是,我没有阅读@yano 的回答。所以我做了自己的基准测试。遗憾的是没有人试图验证这里的假设。我的结果和 yanos 差不多,从某种意义上说,提升 不是几百倍。

On my Macbook Air move is three times faster ( g++ as well as clang++ -std=c++17 -O3 -DNDEBUG ).如果您发现基准测试存在问题,请告诉我。

 #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 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题