黔西南布依族苗族自治州网站建设_网站建设公司_Angular_seo优化
2026/1/16 12:20:51 网站建设 项目流程

1. 核心概念对比

特性std::unique_ptrstd::shared_ptrstd::weak_ptr
所有权独占所有权共享所有权无所有权(弱引用)
拷贝语义不可拷贝,只能移动可拷贝,引用计数增加可拷贝,不增加引用计数
资源释放时机所有者销毁时最后一个shared_ptr销毁时不负责释放资源
性能开销几乎零开销(与裸指针相当)引用计数开销(原子操作)引用计数开销
内存布局单个指针大小两个指针大小(对象指针+控制块指针)单个指针大小
线程安全非线程安全(需外部同步)引用计数操作线程安全,对象访问需同步引用计数操作线程安全

2. 详细特性分析

2.1std::unique_ptr

设计哲学:独占所有权,零开销抽象

// 独占所有权,不能共享std::unique_ptr<int>ptr1=std::make_unique<int>(42);// std::unique_ptr<int> ptr2 = ptr1; // 错误!不能拷贝std::unique_ptr<int>ptr2=std::move(ptr1);// 只能移动转移所有权// 自定义删除器(编译时确定)autodeleter=[](int*p){std::cout<<"Deleting int\n";deletep;};std::unique_ptr<int,decltype(deleter)>ptr3(newint(10),deleter);// 数组版本std::unique_ptr<int[]>arr=std::make_unique<int[]>(10);arr[0]=1;// 支持operator[]

优点

  • 零开销(编译器优化后与裸指针相同)
  • 明确的独占所有权语义
  • 编译时多态(通过自定义删除器模板参数)
  • 适合资源管理、RAII模式

缺点

  • 不能共享所有权
  • 不能用于需要共享的场景

2.2std::shared_ptr

设计哲学:共享所有权,引用计数

#include<memory>#include<iostream>classResource{public:Resource(){std::cout<<"Resource created\n";}~Resource(){std::cout<<"Resource destroyed\n";}};voidusage(){// 创建shared_ptrautosp1=std::make_shared<Resource>();// 引用计数: 1{autosp2=sp1;// 拷贝,引用计数: 2autosp3=sp1;// 拷贝,引用计数: 3std::cout<<"sp1.use_count() = "<<sp1.use_count()<<"\n";// 3}// sp2, sp3销毁,引用计数: 1// 控制块包含:引用计数、弱引用计数、删除器、分配器等std::cout<<"sp1.use_count() = "<<sp1.use_count()<<"\n";// 1}// sp1销毁,引用计数: 0,资源被释放// 循环引用问题示例structNode{std::shared_ptr<Node>next;~Node(){std::cout<<"Node destroyed\n";}};voidcircularReference(){autonode1=std::make_shared<Node>();autonode2=std::make_shared<Node>();node1->next=node2;// 引用计数: node1=1, node2=2node2->next=node1;// 引用计数: node1=2, node2=2 - 循环引用!// 函数结束时,引用计数都变为1,内存泄漏!}// 自定义删除器(运行时确定)voidcustomDeleter(int*p){std::cout<<"Custom delete\n";deletep;}autosp=std::shared_ptr<int>(newint(42),customDeleter);

优点

  • 允许共享所有权
  • 自动管理生命周期
  • 线程安全的引用计数
  • 支持自定义删除器(运行时多态)

缺点

  • 引用计数开销(特别是原子操作)
  • 控制块额外内存开销
  • 可能导致循环引用

2.3std::weak_ptr

设计哲学:弱引用,避免所有权

classObserver;classSubject{std::vector<std::weak_ptr<Observer>>observers;public:voidaddObserver(std::weak_ptr<Observer>obs){observers.push_back(obs);}voidnotify(){for(auto&weakObs:observers){if(autoobs=weakObs.lock()){// 尝试获取shared_ptr// 如果对象还存在,通知它obs->onNotify();}else{// 对象已被释放,可以清理弱引用}}}};classObserver{public:voidonNotify(){std::cout<<"Notified!\n";}};// 使用示例voidobserverPattern(){autosubject=std::make_shared<Subject>();autoobserver=std::make_shared<Observer>();subject->addObserver(observer);// 传递weak_ptr// observer可以在其他地方被释放,不会影响subjectobserver.reset();// 释放observersubject->notify();// 安全,不会访问已释放的对象}// 解决循环引用structSafeNode{std::weak_ptr<SafeNode>next;// 使用weak_ptr避免循环引用~SafeNode(){std::cout<<"SafeNode destroyed\n";}};voidnoCircularReference(){autonode1=std::make_shared<SafeNode>();autonode2=std::make_shared<SafeNode>();node1->next=node2;// weak_ptr不增加引用计数node2->next=node1;// 引用计数保持为1// 函数结束时,两个节点都能正确释放}

优点

  • 打破循环引用
  • 实现观察者模式
  • 缓存实现(不影响对象生命周期)
  • 安全的对象访问(通过lock()检查)

缺点

  • 需要额外步骤获取对象(lock()
  • 不能直接访问对象

3. 性能比较

#include<memory>#include<chrono>#include<iostream>constintITERATIONS=10000000;voidtestUniquePtr(){autostart=std::chrono::high_resolution_clock::now();for(inti=0;i<ITERATIONS;++i){autoptr=std::make_unique<int>(i);// 移动操作autoptr2=std::move(ptr);}autoend=std::chrono::high_resolution_clock::now();std::chrono::duration<double>diff=end-start;std::cout<<"unique_ptr: "<<diff.count()<<"s\n";}voidtestSharedPtr(){autostart=std::chrono::high_resolution_clock::now();for(inti=0;i<ITERATIONS;++i){autoptr=std::make_shared<int>(i);autoptr2=ptr;// 拷贝,引用计数操作autoptr3=ptr;// 再次拷贝}autoend=std::chrono::high_resolution_clock::now();std::chrono::duration<double>diff=end-start;std::cout<<"shared_ptr: "<<diff.count()<<"s\n";}// 典型结果(10,000,000次操作):// unique_ptr: 0.15s// shared_ptr: 1.20s (约8倍慢)

内存布局对比

structObject{intdata[100];};// unique_ptr: 一个指针(8字节)std::unique_ptr<Object>up=std::make_unique<Object>();// shared_ptr: 两个指针(16字节)+ 控制块(~32字节)std::shared_ptr<Object>sp=std::make_shared<Object>();// make_shared将对象和控制块分配在一起,提高局部性// shared_ptr<Object> sp(new Object()); // 分离分配,较差

4. 使用场景总结

使用std::unique_ptr的场景:

// 1. 工厂函数返回std::unique_ptr<Database>createDatabase(){returnstd::make_unique<MySQLDatabase>();}// 2. 独占资源管理classConnection{std::unique_ptr<Socket>socket;// 独占socketstd::unique_ptr<Buffer>buffer;// 独占buffer};// 3. Pimpl惯用法classMyClass{structImpl;std::unique_ptr<Impl>pimpl;};// 4. 容器中的对象std::vector<std::unique_ptr<Shape>>shapes;shapes.push_back(std::make_unique<Circle>());

使用std::shared_ptr的场景:

// 1. 共享缓存classCache{staticstd::unordered_map<std::string,std::shared_ptr<Resource>>cache;staticstd::shared_ptr<Resource>get(conststd::string&key){returncache[key];// 共享所有权}};// 2. 共享配置classAppConfig{std::shared_ptr<Config>config;// 多个组件共享同一配置};// 3. 需要延长对象生命周期的回调classAsyncOperation{std::shared_ptr<Callback>callback;// 确保回调对象在操作完成前存活};// 4. 多线程共享数据classThreadPool{std::shared_ptr<TaskQueue>queue;// 多个工作线程共享任务队列};

使用std::weak_ptr的场景:

// 1. 打破循环引用classParent{std::shared_ptr<Child>child;};classChild{std::weak_ptr<Parent>parent;// 使用weak_ptr};// 2. 观察者模式classSubject{std::vector<std::weak_ptr<Observer>>observers;};// 3. 缓存实现classCache{std::unordered_map<std::string,std::weak_ptr<Resource>>weakCache;std::shared_ptr<Resource>get(conststd::string&key){if(autoit=weakCache.find(key);it!=weakCache.end()){if(autoresource=it->second.lock()){returnresource;// 对象还存在}weakCache.erase(it);// 对象已释放,清理}// 重新加载...}};// 4. 临时对象引用classProcessor{std::weak_ptr<TempData>tempData;// 临时数据,可能被提前释放};

5. 最佳实践总结

  1. 优先使用std::unique_ptr

    • 默认选择,除非需要共享所有权
    • 性能最佳,语义最清晰
  2. 谨慎使用std::shared_ptr

    • 只在真正需要共享所有权时使用
    • 注意循环引用问题
    • 优先使用std::make_shared
  3. 合理使用std::weak_ptr

    • 解决循环引用
    • 实现观察者、缓存等模式
    • 总是通过lock()检查有效性
  4. 选择原则

    • 需要独占所有权 →unique_ptr
    • 需要共享所有权 →shared_ptr
    • 需要弱引用/打破循环 →weak_ptr
    • 原始指针/引用 → 用于无所有权场景
  5. 性能考虑

    • 热点路径避免shared_ptr
    • 小对象考虑使用unique_ptr或直接存储
    • 避免频繁创建/销毁shared_ptr
// 混合使用示例classSystem{private:std::unique_ptr<Database>db;// 独占数据库连接std::shared_ptr<Config>config;// 共享配置std::weak_ptr<Monitor>monitor;// 弱引用监控器(可能不存在)std::vector<std::unique_ptr<Task>>tasks;// 独占任务对象std::shared_ptr<Logger>logger;// 共享日志器};

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询