C++使用PIMPL模式时如何避免shared_ptr的额外性能开销
解决方案
针对你提出的「支持不完整类型、规避std::shared_ptr原子引用计数开销、仅用标准库实现」的核心需求,优先推荐**自定义类型擦除删除器的std::unique_ptr**方案,完美适配PIMPL等常见场景,性能接近原生裸指针,远高于带原子开销的std::shared_ptr。
方案1:带类型擦除删除器的std::unique_ptr
你之前对std::unique_ptr动态删除器的认知存在偏差:只要在构造std::unique_ptr时目标类型是完整的,就可以将销毁逻辑预存在删除器中,实现对不完整类型的支持,示例实现如下,完全适配你给出的std::fstream测试场景:
头文件(仅声明不完整类型)
#include <memory> #include <iosfwd> // 对外暴露的类型,此时std::fstream为不完整类型 class FileHandler { public: FileHandler(); ~FileHandler(); // 按需实现移动构造/赋值,默认禁用拷贝即可 FileHandler(FileHandler&&) = default; FileHandler& operator=(FileHandler&&) = default; private: // 用函数指针作为删除器实现类型擦除,不需要知道std::fstream的完整定义 std::unique_ptr<std::fstream, void(*)(std::fstream*)> _file; };
实现文件(类型完整时构造智能指针)
#include <fstream> FileHandler::FileHandler() // 此时std::fstream是完整类型,lambda内部已经明确知道如何销毁对象 : _file(new std::fstream, [](std::fstream* ptr) { delete ptr; }) {} FileHandler::~FileHandler() = default;
该方案的核心优势:
- 无原子引用计数开销,仅多一次删除器的间接调用,性能损失可以忽略
- 完美支持不完整类型,完全适配PIMPL场景
- 支持move-only类型(比如
std::fstream),弥补了std::any要求类型可拷贝的缺陷 - 完全基于标准库原生组件,无第三方依赖
方案2:需要共享所有权的场景
当前C++标准库没有提供官方的非原子版本std::shared_ptr,如果你的场景确实需要共享所有权、且完全不需要线程安全,可以自行实现一个极简的非原子引用计数智能指针,代码量不到100行,性能远高于标准std::shared_ptr,可以完全替代boost的非原子shared_ptr方案。
内容的提问来源于stack exchange,提问作者NoSenseEtAl
相关产品推荐
相关产品推荐

