unique_ptr独占资源所有权,无引用计数,性能高;shared_ptr共享所有权,通过引用计数管理生命周期,但有性能开销和循环引用风险。

C++内存管理中,
unique_ptr
shared_ptr
unique_ptr
shared_ptr
当我们在C++中谈论内存管理,尤其是在现代C++的语境下,智能指针是绕不开的话题。它们被设计出来,就是为了解决传统裸指针带来的内存泄漏、悬空指针等一系列头疼问题,将资源管理自动化。但
unique_ptr
shared_ptr
unique_ptr
unique_ptr
unique_ptr
unique_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
立即学习“C++免费学习笔记(深入)”;
unique_ptr
shared_ptr
“轻量”这个词,在
unique_ptr
unique_ptr
unique_ptr
比如,一个函数内部创建的对象,或者一个类成员变量,它只由该类实例拥有和管理,那么
unique_ptr
unique_ptr
unique_ptr
// 示例:unique_ptr作为函数返回值,转移所有权
std::unique_ptr<MyObject> createObject() {
// MyObject的创建和管理完全由unique_ptr负责
return std::make_unique<MyObject>();
}
// 示例:类成员变量,独占资源
class ResourceManager {
private:
std::unique_ptr<Resource> _resource; // 资源由ResourceManager独占
public:
ResourceManager() : _resource(std::make_unique<Resource>()) {
// ...
}
// ...
};这种独占性让代码意图更加清晰,也避免了不必要的开销。
shared_ptr
shared_ptr
shared_ptr
shared_ptr
然而,这种“甜蜜”并非没有代价。首先是性能开销,引用计数的增减通常需要原子操作来保证多线程环境下的正确性,这比简单的指针赋值要慢。其次,也是更隐蔽且棘手的问题:循环引用(circular dependency)。如果对象A持有一个指向B的
shared_ptr
shared_ptr
shared_ptr
// 示例:循环引用问题
class B; // 前向声明
class A {
public:
std::shared_ptr<B> b_ptr;
~A() { std::cout << "A destroyed" << std::endl; }
};
class B {
public:
// 如果这里是shared_ptr,就会形成循环引用
std::shared_ptr<A> a_ptr;
~B() { std::cout << "B destroyed" << std::endl; }
};
void demonstrateCircularReference() {
auto a = std::make_shared<A>();
auto b = std::make_shared<B>();
a->b_ptr = b; // b的引用计数变为2 (a->b_ptr和b)
b->a_ptr = a; // a的引用计数变为2 (b->a_ptr和a)
// 当a和b离开作用域时,它们的引用计数会减到1,但不会到0,导致内存泄漏
}解决循环引用通常需要引入
weak_ptr
weak_ptr
shared_ptr
shared_ptr
lock()
lock()
shared_ptr
// 解决循环引用:使用weak_ptr
class B_Fixed;
class A_Fixed {
public:
std::shared_ptr<B_Fixed> b_ptr;
~A_Fixed() { std::cout << "A_Fixed destroyed" << std::endl; }
};
class B_Fixed {
public:
std::weak_ptr<A_Fixed> a_ptr; // 使用weak_ptr打破循环
~B_Fixed() { std::cout << "B_Fixed destroyed" << std::endl; }
};
void demonstrateFixedCircularReference() {
auto a = std::make_shared<A_Fixed>();
auto b = std::make_shared<B_Fixed>();
a->b_ptr = b; // b的引用计数为1
b->a_ptr = a; // a的引用计数为1 (weak_ptr不增加计数)
// 当a和b离开作用域时,引用计数会正确降到0,资源会被释放
}weak_ptr
std::make_unique
std::make_shared
在现代C++编程中,直接使用
new
std::make_unique
std::make_shared
最主要的陷阱在于异常安全性。考虑这样一个函数调用:
foo(std::shared_ptr<T>(new T()), functionThatMightThrow());
new T()
std::shared_ptr<T>
functionThatMightThrow()
new T()
functionThatMightThrow()
std::shared_ptr<T>
new T()
shared_ptr
而
std::make_shared<T>()
std::make_unique<T>()
make_shared
make_unique
此外,
std::make_shared
new T()
shared_ptr
std::make_unique
因此,我的建议是,除非有非常特殊的原因(比如需要自定义删除器或者从已有的裸指针接管),否则总是优先使用
std::make_unique
std::make_shared
// 避免潜在陷阱的示例 // 不推荐:可能导致内存泄漏 // foo(std::shared_ptr<MyObject>(new MyObject()), potentially_throwing_function()); // 推荐:异常安全且高效 // foo(std::make_shared<MyObject>(), potentially_throwing_function()); // std::make_unique的创建示例 auto myUniqueObj = std::make_unique<MyObject>(); // std::make_unique也可以用于数组 auto myUniqueArray = std::make_unique<MyObject[]>(10);
这些辅助函数不仅让代码更健壮,也更清晰地表达了程序员的意图。它们是C++智能指针生态中不可或缺的一部分。
以上就是C++内存管理基础中unique_ptr与shared_ptr区别的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号