You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何初始化std::shared_ptr成员?两种方式的性能对比

C++中std::shared_ptr成员初始化的性能对比

两种初始化方式

以下两种方式都会增加std::shared_ptr的引用计数:

1. 传递const引用(兼容左值与临时对象)

最初的版本仅支持左值引用,无法直接接收std::make_shared创建的临时对象,更新为const引用后可同时兼容两种场景:

class MyClass {
    std::shared_ptr<std::string> s1;
public:
    MyClass(const std::shared_ptr<std::string>& s2): s1{s2} {}
};

2. 传递值并移动

通过传值构造参数,再利用std::move将参数转移到成员变量中:

class MyClass2 {
    std::shared_ptr<std::string> s1;
public:
    MyClass2(std::shared_ptr<std::string> s2): s1{std::move(s2)} {}
};

基础引用计数验证

测试两种方式对引用计数的影响:

int main() {
    std::shared_ptr<std::string> s2 = std::make_shared<std::string>("Hello World");
    MyClass myClass {s2};
    MyClass2 myClass2 {s2};
    
    std::cout << "Use count:" << s2.use_count() << std::endl;
        
    return 0;
}

测试结果:

Use count:3

两种方式均会使引用计数+1,最终s2的引用计数为自身、MyClass成员、MyClass2成员三者之和。

性能对比疑问

第二种方式多了一次移动操作,看起来没有优势,那从性能角度出发,哪种初始化方式更优?

大规模循环基准测试

在千万次循环场景下验证性能差异:

#include <iostream>
#include <memory>
#include <chrono>

using namespace std;

class MyClass {
    std::shared_ptr<std::string> s1;
public:
    MyClass(const std::shared_ptr<std::string>& s2): s1{s2} {}
};

class MyClass2 {
    std::shared_ptr<std::string> s1;
public:
    MyClass2(std::shared_ptr<std::string> s2): s1{std::move(s2)} {}
};


int main() {
    std::shared_ptr<std::string> s2 = std::make_shared<std::string>("Hello World");
    
    auto start = std::chrono::high_resolution_clock::now();
    
    for (int i = 0; i < 10000000; i++) {
        MyClass myClass {s2};
    }    
    auto end = std::chrono::high_resolution_clock::now();
    
    std::chrono::duration<float> duration = end - start;
    std::cout << duration.count() << std::endl;
    
    
    
    start = std::chrono::high_resolution_clock::now();
    
    for (int i = 0; i < 10000000; i++) {
        MyClass2 myClass2 {s2};
    }    
    end = std::chrono::high_resolution_clock::now();
    
    duration = end - start;
    std::cout << duration.count() << std::endl;    
        
    return 0;
}

测试结果(C++17在线编译器)

0.358915
0.623789

结论

从测试结果可明确看出,传递const引用的方式性能更优。原因在于:

  • 传const引用初始化时,仅需执行一次引用计数的原子递增操作;
  • 传值再移动的方式,首先要对左值参数执行一次拷贝(原子递增引用计数),再执行移动操作(虽轻量但仍有额外开销),整体开销高于直接传引用。

当然传值方式并非完全无用:若需同时支持左值、右值传入且避免重复重载函数,可考虑传值再移动,但仅处理左值的场景下,传const引用的性能优势是明确的。

内容的提问来源于stack exchange,提问作者Metropol_Tilkisi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 20:50:38