c++++11引入智能指针的核心目的是解决传统手动内存管理带来的内存泄漏、野指针、重复释放等问题,并通过raii机制实现资源的自动管理和释放。1. 内存泄漏:智能指针将资源生命周期绑定到对象生命周期,离开作用域后自动释放资源;2. 野指针:智能指针在销毁时自动置空内部原始指针,防止误用悬空指针;3. 重复释放:unique_ptr通过独占所有权避免重复释放,shared_ptr通过引用计数确保资源只被释放一次;4. 异常安全:栈上智能指针无论函数正常返回或异常退出都会被销毁,保证资源释放;5. 提升代码可读性和维护性:封装内存管理逻辑,使代码更简洁清晰。

C++11引入的智能指针主要有
std::unique_ptr
std::shared_ptr
new
delete

在我看来,C++11的智能指针是现代C++编程中不可或缺的一部分,它们彻底改变了我们处理动态内存的方式。理解
unique_ptr
shared_ptr

std::unique_ptr
立即学习“C++免费学习笔记(深入)”;
unique_ptr
unique_ptr
unique_ptr

核心特性:
std::move
delete
使用场景:
unique_ptr
std::vector<std::unique_ptr<T>>
unique_ptr
示例:
#include <memory>
#include <iostream>
class MyObject {
public:
MyObject() { std::cout << "MyObject constructed!\n"; }
~MyObject() { std::cout << "MyObject destroyed!\n"; }
void doSomething() { std::cout << "Doing something...\n"; }
};
// 工厂函数返回unique_ptr
std::unique_ptr<MyObject> createObject() {
return std::make_unique<MyObject>(); // 推荐使用make_unique
}
void processObject(std::unique_ptr<MyObject> obj) {
if (obj) {
obj->doSomething();
}
// obj超出作用域时自动销毁MyObject
}
int main() {
auto p1 = createObject(); // p1拥有MyObject
p1->doSomething();
auto p2 = std::move(p1); // 所有权从p1转移到p2,p1现在为空
if (!p1) {
std::cout << "p1 is now empty.\n";
}
p2->doSomething();
processObject(std::move(p2)); // 所有权转移给函数参数,函数结束后销毁
// p2现在为空
return 0;
}std::shared_ptr
shared_ptr
shared_ptr
shared_ptr
核心特性:
shared_ptr
shared_ptr
unique_ptr
weak_ptr
使用场景:
shared_ptr
weak_ptr
示例:
#include <memory>
#include <iostream>
#include <vector>
class Resource {
public:
Resource() { std::cout << "Resource acquired!\n"; }
~Resource() { std::cout << "Resource released!\n"; }
void use() { std::cout << "Using resource.\n"; }
};
void consumer(std::shared_ptr<Resource> res) {
std::cout << "Consumer: current ref count = " << res.use_count() << "\n";
res->use();
} // res超出作用域,引用计数减一
int main() {
std::shared_ptr<Resource> r1 = std::make_shared<Resource>(); // 推荐使用make_shared
std::cout << "r1 ref count = " << r1.use_count() << "\n"; // 1
std::shared_ptr<Resource> r2 = r1; // 复制,引用计数增加
std::cout << "r1 ref count = " << r1.use_count() << "\n"; // 2
std::cout << "r2 ref count = " << r2.use_count() << "\n"; // 2
consumer(r1); // 传递副本,引用计数临时增加到3,函数返回后减回2
std::vector<std::shared_ptr<Resource>> resources;
resources.push_back(r1); // 引用计数增加到3
std::cout << "r1 ref count after push_back = " << r1.use_count() << "\n"; // 3
r1.reset(); // r1不再指向Resource,引用计数减一
std::cout << "r1 is null: " << (r1 == nullptr) << "\n"; // true
std::cout << "r2 ref count after r1 reset = " << r2.use_count() << "\n"; // 2
// 当r2和resources中的shared_ptr都销毁时,Resource才会被释放
return 0;
}说实话,C++11引入智能指针,在我看来,是C++语言发展史上一个里程碑式的改进。在此之前,手动管理内存简直是“痛点”的代名词。我们得小心翼翼地配对
new
delete
delete
智能指针的出现,正是为了解决这些“老大难”问题:
内存泄漏: 这是最常见的,也是最让人头疼的问题。忘记
delete
delete
野指针/悬空指针: 当一个对象被
delete
shared_ptr
重复释放(Double Free): 对同一块内存进行两次
delete
unique_ptr
shared_ptr
异常安全: 在没有智能指针的情况下,如果在函数执行过程中抛出异常,那么在异常点之后的
delete
代码可读性和维护性: 显式的
new
delete
在我看来,智能指针不仅仅是语法糖,它们是C++内存管理哲学的一次深刻变革,让C++在保持高性能的同时,也能拥有接近GC语言的内存安全性。
unique_ptr
shared_ptr
这就像是给你的代码选工具,趁手不趁手,效率差很多。选择
unique_ptr
shared_ptr
unique_ptr
unique_ptr
shared_ptr
unique_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
如何选择?
我的建议是,优先使用unique_ptr
shared_ptr
选择unique_ptr
unique_ptr
std::vector<std::unique_ptr<T>>
选择shared_ptr
shared_ptr
总的来说,
unique_ptr
shared_ptr
weak_ptr
智能指针确实是现代C++的利器,但就像任何强大的工具一样,如果使用不当,也可能带来新的问题。我个人在项目里也踩过一些坑,其中最典型的就是
shared_ptr
常见的陷阱:
shared_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
示例:
#include <memory>
#include <iostream>
class B; // 前向声明
class A {
public:
std::shared_ptr<B> b_ptr;
A() { std::cout << "A constructed!\n"; }
~A() { std::cout << "A destroyed!\n"; }
};
class B {
public:
std::shared_ptr<A> a_ptr;
B() { std::cout << "B constructed!\n"; }
~B() { std::cout << "B destroyed!\n"; }
};
void create_circular_ref() {
auto a = std::make_shared<A>();
auto b = std::make_shared<B>();
a->b_ptr = b; // A持有B
b->a_ptr = a; // B持有A,形成循环
// 当a和b超出作用域时,它们的引用计数都是1,永远不会降为0,A和B都不会被销毁。
} // 内存泄漏发生在这里
int main() {
create_circular_ref();
std::cout << "Back in main, objects might have leaked if not handled.\n";
return 0;
}从原始指针创建多个shared_ptr
shared_ptr
shared_ptr
shared_ptr
int* raw_ptr = new int(10); std::shared_ptr<int> s1(raw_ptr); std::shared_ptr<int> s2(raw_ptr); // 危险!s1和s2会独立管理同一个raw_ptr,导致重复释放
在构造函数中返回shared_ptr<this>
shared_ptr<MyClass>(this)
shared_ptr
this
混合使用原始指针和智能指针: 当一个资源同时被原始指针和智能指针管理时,很容易出错。智能指针可能在原始指针还在使用时就释放了资源,导致野指针。
最佳实践和解决方案:
解决循环引用:std::weak_ptr
weak_ptr
shared_ptr
shared_ptr
shared_ptr
weak_ptr
原理: 在循环引用中,让其中一个指针(通常是父子关系中的子指向父,或者相互依赖关系中较弱的一方)使用
weak_ptr
weak_ptr
使用方式: 你需要通过
weak_ptr::lock()
shared_ptr
lock()
shared_ptr
shared_ptr
示例(修改上面的循环引用):
#include <memory>
#include <iostream>
class B;
class A {
public:
std::shared_ptr<B> b_ptr;
A() { std::cout << "A constructed!\n"; }
~A() { std::cout << "A destroyed!\n"; }
};
class B {
public:
std::weak_ptr<A> a_ptr; // 使用weak_ptr打破循环
B() { std::cout << "B constructed!\n"; }
~B() { std::cout << "B destroyed!\n"; }
};
void create_non_circular_ref() {
auto a = std::make_shared<A>();
auto b = std::make_shared<B>();
a->b_ptr = b; // A持有B (shared_ptr)
b->a_ptr = a; // B观察A (weak_ptr),不增加A的引用计数
// 当a和b超出作用域时,a的引用计数会降到0(因为b_ptr是shared_ptr),A被销毁。
// A销毁后,b->a_ptr会失效。然后b的引用计数也降到0,B被销毁。
}
int main() {
create_non_circular_ref();
std::cout << "Back in main, objects should be destroyed.\n";
return 0;
}使用std::make_unique
std::make_shared
以上就是C++11的智能指针有哪些类型 shared_ptr unique_ptr使用场景分析的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号