C++11 智能指针及其使用方法详细总结
C++11 引入了几种智能指针,包括 std::unique_ptr
, std::shared_ptr
, 和 std::weak_ptr
,用于简化动态内存管理,避免内存泄漏和悬挂指针问题。以下是每种智能指针的详细介绍及其使用方法。
1. std::unique_ptr
std::unique_ptr
是一种独占所有权的智能指针,不能被复制,但可以移动。它确保在其生命周期结束时自动释放所管理的对象。
-
创建和初始化:
// 使用 std::make_unique (推荐方法,C++14 引入) auto ptr = std::make_unique<int>(10);// 使用 new (不推荐) std::unique_ptr<int> ptr(new int(10));
-
所有权转移:
std::unique_ptr<int> ptr1 = std::make_unique<int>(10); std::unique_ptr<int> ptr2 = std::move(ptr1); // ptr1 变为空指针
-
释放对象:
ptr.reset(); // 释放对象并将 ptr 置为空指针
-
获取裸指针:
int* rawPtr = ptr.get(); // 获取裸指针,不会释放对象
-
解引用:
std::cout << *ptr << std::endl; // 访问所管理对象的值
2. std::shared_ptr
std::shared_ptr
是一种共享所有权的智能指针,通过引用计数来管理对象的生命周期。当最后一个 std::shared_ptr
被销毁时,所管理的对象才会被释放。
-
创建和初始化:
// 使用 std::make_shared (推荐方法) auto ptr = std::make_shared<int>(10);// 使用 new (不推荐) std::shared_ptr<int> ptr(new int(10));
-
引用计数:
std::cout << ptr.use_count() << std::endl; // 获取引用计数
-
检查唯一所有者:
std::cout << std::boolalpha << ptr.unique() << std::endl; // 是否唯一所有者
-
释放对象:
ptr.reset(); // 释放对象并将 ptr 置为空指针,如果引用计数降为零则销毁对象
-
获取裸指针:
int* rawPtr = ptr.get(); // 获取裸指针,不会释放对象
-
解引用:
std::cout << *ptr << std::endl; // 访问所管理对象的值
3. std::weak_ptr
std::weak_ptr
是一种不控制对象生命周期的智能指针,必须与 std::shared_ptr
一起使用,通常用于解决循环引用问题。它不会增加引用计数。
-
创建和初始化:
std::shared_ptr<int> sharedPtr = std::make_shared<int>(10); std::weak_ptr<int> weakPtr = sharedPtr;
-
检查对象是否已被销毁:
std::cout << std::boolalpha << weakPtr.expired() << std::endl; // 对象是否被销毁
-
提升为 shared_ptr:
if (auto lockedPtr = weakPtr.lock()) {std::cout << *lockedPtr << std::endl; // 成功提升并访问对象 } else {std::cout << "Object has been destroyed." << std::endl; }
-
释放 weak_ptr:
weakPtr.reset(); // 将 weak_ptr 置为空
-
获取引用计数:
std::cout << weakPtr.use_count() << std::endl; // 获取引用计数
安全性和性能优化
使用 std::make_unique
和 std::make_shared
相比直接使用 new
更安全且性能更高:
-
异常安全性:
std::make_unique
和std::make_shared
在分配和构造对象时是一个原子操作,避免了使用new
时可能的内存泄漏问题。例如:auto ptr1 = std::make_unique<int>(10); auto ptr2 = std::make_unique<int>(20); // 即使这里抛出异常,ptr1 也不会泄漏
-
性能优化:
std::make_shared
通过将控制块和对象本身分配在同一块内存中,减少了内存分配次数,提高了性能。例如:auto ptr = std::make_shared<int>(10); // 一次内存分配
-
简洁性和可读性:使用
std::make_unique
和std::make_shared
使代码更简洁:auto ptr = std::make_unique<int>(10); // 简洁且安全
总结
-
智能指针类型:
std::unique_ptr
:独占所有权,不能复制,只能移动。std::shared_ptr
:共享所有权,通过引用计数管理对象生命周期。std::weak_ptr
:不控制对象生命周期,用于解决循环引用问题。
-
推荐的初始化方法:
std::make_unique
(C++14 引入):推荐用于std::unique_ptr
。std::make_shared
:推荐用于std::shared_ptr
。
-
常用 API:
reset()
:释放对象并置空。release()
(仅适用于std::unique_ptr
):释放控制权并返回裸指针。get()
:返回裸指针。use_count()
(适用于std::shared_ptr
和std::weak_ptr
):返回引用计数。unique()
(适用于std::shared_ptr
):检查是否是唯一所有者。lock()
(适用于std::weak_ptr
):尝试提升为std::shared_ptr
。expired()
(适用于std::weak_ptr
):检查所指对象是否已被销毁。
通过智能指针和这些 API,可以有效地管理动态内存,避免内存泄漏和悬挂指针问题,提升代码的安全性和可维护性。