优先使用unique_ptr,因其性能开销最小且语义清晰;仅在需要共享所有权时使用shared_ptr,以避免不必要的性能损耗和循环引用风险。

在C++项目中选择使用
unique_ptr
shared_ptr
unique_ptr
shared_ptr
unique_ptr
shared_ptr
在C++现代编程中,智能指针是管理动态内存不可或缺的工具,它们极大地简化了资源管理,避免了内存泄漏和悬空指针等常见问题。
unique_ptr
shared_ptr
从我个人的经验来看,很多初学者,甚至一些有经验的开发者,在面对动态内存管理时,会不自觉地倾向于
shared_ptr
unique_ptr
unique_ptr
unique_ptr
unique_ptr
unique_ptr
立即学习“C++免费学习笔记(深入)”;
而
shared_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
选择的关键在于你对资源所有权的预期。如果一个对象应该只有一个明确的“主人”,并且这个主人负责它的生老病死,那么
unique_ptr
shared_ptr
unique_ptr
在我看来,
unique_ptr
unique_ptr
具体来说,
unique_ptr
零运行时开销: 这是它最吸引人的地方。
unique_ptr
delete
shared_ptr
明确的所有权语义: 它强制执行独占所有权。你不能简单地复制一个
unique_ptr
std::move
更好的局部性: 通常,
unique_ptr
作为工厂函数的返回值:
unique_ptr
unique_ptr
std::unique_ptr<MyClass> createMyClass() {
return std::make_unique<MyClass>();
}
void process() {
std::unique_ptr<MyClass> obj = createMyClass();
// obj 独占 MyClass 实例
}作为类成员: 当一个类内部拥有一个资源,并且这个资源的生命周期与类实例的生命周期绑定时,
unique_ptr
class ResourceManager {
std::unique_ptr<Resource> resource_;
public:
ResourceManager() : resource_(std::make_unique<Resource>()) {}
// ...
};我个人觉得,如果你发现自己在使用
shared_ptr
unique_ptr
shared_ptr
unique_ptr
尽管我强调
unique_ptr
shared_ptr
unique_ptr
以下是一些必须使用
shared_ptr
真正的共享所有权: 这是最核心的场景。当多个对象确实需要共同拥有一个资源的生命周期时,也就是说,只要这些对象中任何一个还存在,资源就不能被释放,那么
shared_ptr
struct Node {
int value;
std::vector<std::shared_ptr<Node>> neighbors; // 邻居共享所有权
Node(int v) : value(v) {}
};std::shared_ptr
回调函数和异步操作: 在异步编程或使用回调函数时,一个对象可能需要在原始作用域结束后仍然存活,以便回调函数能够安全地访问它。
class MyService {
std::shared_ptr<Data> data_;
public:
MyService(std::shared_ptr<Data> d) : data_(d) {}
void startAsyncProcess() {
// 假设这是一个异步任务,它需要访问 data_
// data_ 必须在异步任务完成前保持存活
std::thread([this_ptr = data_]() { // 使用拷贝捕获 shared_ptr
// 异步操作,安全地访问 *this_ptr
std::cout << "Async process using data: " << this_ptr->getValue() << std::endl;
}).detach();
}
};这里,
data_
shared_ptr
Data
STL容器存储多态对象: 当你需要在一个STL容器中存储指向多态基类的指针,并且这些对象的生命周期需要被容器管理时,
shared_ptr
std::vector<std::shared_ptr<BaseClass>> objects; objects.push_back(std::make_shared<DerivedClassA>()); objects.push_back(std::make_shared<DerivedClassB>()); // 容器销毁时,所有对象也会被销毁
使用
shared_ptr
shared_ptr
unique_ptr
shared_ptr
weak_ptr
shared_ptr
shared_ptr
shared_ptr
举个例子,假设我们有一个父子关系:父节点拥有子节点,子节点也需要引用父节点。
struct Child; // 前向声明
struct Parent {
std::shared_ptr<Child> child;
~Parent() { std::cout << "Parent destroyed!" << std::endl; }
};
struct Child {
std::shared_ptr<Parent> parent; // 问题所在!
~Child() { std::cout << "Child destroyed!" << std::endl; }
};
void createCycle() {
std::shared_ptr<Parent> p = std::make_shared<Parent>();
std::shared_ptr<Child> c = std::make_shared<Child>();
p->child = c; // p 拥有 c
c->parent = p; // c 拥有 p
// 此时 p 的引用计数为 2 (p 和 c->parent)
// c 的引用计数为 2 (c 和 p->child)
} // p 和 c 离开作用域,引用计数各自减 1,但都仍为 1,导致内存泄漏当
createCycle
p
c
shared_ptr
p
c->parent
c
p->child
Parent
Child
为了解决这个问题,C++标准库引入了
std::weak_ptr
weak_ptr
shared_ptr
weak_ptr
weak_ptr
weak_ptr
weak_ptr
lock()
shared_ptr
shared_ptr
lock()
shared_ptr
shared_ptr
修改上述循环引用示例:
struct Child; // 前向声明
struct Parent {
std::shared_ptr<Child> child;
~Parent() { std::cout << "Parent destroyed!" << std::endl; }
};
struct Child {
std::weak_ptr<Parent> parent; // 使用 weak_ptr 引用父节点
~Child() { std::cout << "Child destroyed!" << std::endl; }
void accessParent() {
if (auto p_locked = parent.lock()) { // 尝试锁定为 shared_ptr
std::cout << "Child is accessing a live parent." << std::endl;
} else {
std::cout << "Parent has been destroyed." << std::endl;
}
}
};
void createNoCycle() {
std::shared_ptr<Parent> p = std::make_shared<Parent>();
std::shared_ptr<Child> c = std::make_shared<Child>();
p->child = c; // Parent 拥有 Child
c->parent = p; // Child 弱引用 Parent
// 此时 p 的引用计数为 1 (p)
// c 的引用计数为 2 (c 和 p->child)
} // p 和 c 离开作用域,引用计数各自减 1,最终都会降到 0,对象被正确销毁在这个修正后的版本中,
Parent
shared_ptr
Child
Child
Parent
Child
weak_ptr
Parent
Parent
createNoCycle
p
c
shared_ptr
p
Parent
Parent
Child
c
Child
所以,在设计数据结构时,如果发现有相互引用的情况,并且其中一个引用不应该承担所有权责任,那么
weak_ptr
unique_ptr
shared_ptr
在性能敏感的场景下,
unique_ptr
shared_ptr
unique_ptr
unique_ptr
unique_ptr
std::make_unique
delete
unique_ptr
shared_ptr
shared_ptr
std::make_shared
std::shared_ptr<T>(new T())
shared_ptr
std::make_shared
shared_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
量化差异: 具体性能差异很难给出精确的数字,因为它高度依赖于CPU架构、编译器优化、内存子系统性能以及具体的使用模式。但大致上,我们可以这样理解:
shared_ptr
make_shared
shared_ptr
unique_ptr
总结: 对于大多数业务逻辑代码,
shared_ptr
unique_ptr
shared_ptr
我的建议是,始终从
unique_ptr
shared_ptr
shared_ptr
std::make_shared
unique_ptr
weak_ptr
以上就是在C++项目中如何选择使用unique_ptr还是shared_ptr的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号