C++ 智能指针是C++标准库提供的类模板,用于自动管理动态分配的对象的生命周期。它们旨在解决传统原始指针可能导致的内存泄漏和资源未正确释放等问题,通过封装对动态内存的访问和控制,实现自动化的资源清理。以下是对C++中几种主要智能指针类型的详细介绍:
1. std::unique_ptr (C++11)
原理与特点:
表现为独占所有权(exclusive ownership)的智能指针。任何时候只有一个unique_ptr实例可以拥有并管理某个对象。
- 当unique_ptr离开其作用域或被显式重置时,它会自动删除其所指向的对象。
- 不支持复制构造函数和赋值操作符,但可以通过转移语义(move semantics)进行移动构造和移动赋值,转移过程中原unique_ptr变为空指针,所有权转移到新unique_ptr。
- 可以直接或间接管理非数组类型以及数组类型。
成员函数:
- release():释放所有权,返回指向对象的原始指针,之后unique_ptr变为空。
- reset():释放当前所拥有的对象(如果存在),可选地接受一个新的裸指针来接管。
- get():返回指向对象的原始指针,但不改变所有权。
- operator->() 和 operator*():提供对托管对象的直接访问。
案例
#include <memory>
// 1.创建一个指向整型对象的unique_ptr,默认使用delete运算符释放资源
std::unique_ptr<int> uptr(new int(10));
// 2.C++ 14 使用 std::make_unique
std::unique_ptr<int> uptr = std::make_unique<int>(10);
std::unique_ptr<MyClass> uptr = std::make_unique<MyClass>();
// 3.转移所有权
int* raw_ptr = new int(10);
std::unique_ptr<int> uptr(raw_ptr);
// 如果uptr已有对象,先释放旧对象,再转移所有权
uptr.reset(raw_ptr);
2. std::shared_ptr (C++11)
原理与特点:
实现共享所有权(shared ownership)的智能指针。多个shared_ptr实例可以同时指向并共享同一个对象。
- 内部维护一个引用计数(reference count)。每当新的shared_ptr拷贝或赋值现有shared_ptr时,引用计数递增;当shared_ptr销毁或重置时,引用计数递减。当引用计数降至零时,自动删除所管理的对象。
- 支持弱引用计数,通过std::weak_ptr关联到同一对象,但不会增加引用计数。
成员函数:
- use_count():返回当前共享对象的引用计数值。
- reset():释放当前所拥有的对象(如果存在),可选地接受一个新的裸指针来接管。
- get():返回指向对象的原始指针,但不改变所有权。
- operator->() 和 operator*():提供对托管对象的直接访问。
swap():交换两个shared_ptr的内容。
与std::make_shared一起使用可以提高效率和减少内存碎片。
3. std::weak_ptr (C++11)
原理与特点:
- 提供对std::shared_ptr管理对象的弱引用,不增加引用计数。
- 可以检查所指向的对象是否仍然存活(未被删除)。
- 通过调用lock()方法临时获取一个可访问对象的shared_ptr,如果对象已被删除,则返回空shared_ptr。
成员函数:
- expired():返回对象是否已被删除(即引用计数是否为零)。
- lock():尝试获取一个指向对象的shared_ptr,如果对象仍然有效,则返回非空shared_ptr,否则返回空shared_ptr。
基本用法
//1 创建
int main() {
// 创建一个 shared_ptr 并指向新建的 MyClass 对象
std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>(42);
// 访问对象的方法
std::cout << "Value: " << ptr1->GetValue() << std::endl;
// 创建另一个 shared_ptr,共享 ptr1 所指向的对象
std::shared_ptr<MyClass> ptr2(ptr1);
// 当 ptr1 和 ptr2 都离开作用域时,MyClass 对象会被自动释放
}
// 2 共享
int main() {
std::shared_ptr<MyClass> ptr = std::make_shared<MyClass>(13);
// 将 ptr 传递给函数,共享所有权
PrintValue(ptr);
// 即使 PrintValue 结束,对象也不会被释放,因为 ptr 仍在作用域内
}
4. std::auto_ptr (已弃用, C++98)
注意:
std::auto_ptr是C++98引入的智能指针类型,但在C++11中已被废弃,取而代之的是std::unique_ptr。由于其转移所有权的行为不符合现代C++的预期(如不支持容器),不再推荐使用。
5. 综上
C++智能指针根据不同的所有权语义分为unique_ptr(独占所有权)、shared_ptr(共享所有权)和weak_ptr(弱引用),它们分别适用于不同的资源管理场景,有助于编写更安全、更易于维护的C++代码。使用智能指针时应遵循其设计意图,正确处理所有权转移和生命周期管理,避免循环引用等潜在问题。