智能指针是 C++ 中的一种数据结构,用于管理动态分配的内存资源,以减少内存泄漏和悬空指针等问题。智能指针在 C++11 标准中引入,并且是标准库中的一部分。它们通过在内部封装原始指针,并提供额外的功能来提高内存管理的安全性和效率。
常见的智能指针有 std::unique_ptr、std::shared_ptr 和 std::weak_ptr。
std::unique_ptr
- 独占所有权:std::unique_ptr 不能被复制,只能通过移动来转移所有权。
#include <memory>
#include <iostream>
int main() {
// 创建一个独占所有权的 unique_ptr
std::unique_ptr<int> uniquePtr(new int(42));
// 尝试复制 unique_ptr 会导致编译错误
// std::unique_ptr<int> anotherPtr = uniquePtr; // 错误
// 可以通过移动来转移所有权
std::unique_ptr<int> anotherPtr = std::move(uniquePtr);
// uniquePtr 不再拥有资源
if (!uniquePtr) {
std::cout << "uniquePtr 不再拥有资源" << std::endl;
}
return 0;
}
- 资源自动释放:当 std::unique_ptr 被销毁时,它所管理的资源会被自动释放,无需手动释放资源。
#include <memory>
#include <iostream>
int main() {
{
// 创建一个独占所有权的 unique_ptr
std::unique_ptr<int> uniquePtr(new int(42));
} // uniquePtr 超出作用域,资源自动释放
std::cout << "资源已释放" << std::endl;
return 0;
}
- 适合用于动态分配的单一对象或对象数组的所有权管理:std::unique_ptr 可以管理单个对象或对象数组的动态分配内存。
#include <memory>
#include <iostream>
int main() {
// 创建一个独占所有权的 unique_ptr,用于动态分配单个对象
std::unique_ptr<int> singleObjectPtr(new int(42));
// 创建一个独占所有权的 unique_ptr,用于动态分配对象数组
std::unique_ptr<int[]> arrayPtr(new int[5]{1, 2, 3, 4, 5});
// 使用 unique_ptr 访问动态分配的对象或对象数组
std::cout << *singleObjectPtr << std::endl; // 输出 42
std::cout << arrayPtr[2] << std::endl; // 输出 3
return 0;
}
std::shared_ptr
- 共享所有权:std::shared_ptr 可以被多个 std::shared_ptr 实例共享。
#include <memory>
#include <iostream>
int main() {
// 创建一个共享所有权的 shared_ptr,初始引用计数为1
std::shared_ptr<int> sharedPtr1(new int(42));
// 创建另一个 shared_ptr,与前一个共享同一个资源
std::shared_ptr<int> sharedPtr2 = sharedPtr1;
// 输出引用计数
std::cout << "sharedPtr1 引用计数: " << sharedPtr1.use_count() << std::endl;
std::cout << "sharedPtr2 引用计数: " << sharedPtr2.use_count() << std::endl;
return 0;
}
- 使用引用计数管理资源:std::shared_ptr 使用引用计数来管理资源,当最后一个 std::shared_ptr 被销毁时,资源被释放。
#include <memory>
#include <iostream>
int main() {
std::shared_ptr<int> sharedPtr(new int(42));
// 输出引用计数
std::cout << "初始引用计数: " << sharedPtr.use_count() << std::endl;
{
// 创建另一个 shared_ptr,引用计数增加
std::shared_ptr<int> anotherPtr = sharedPtr;
std::cout << "引用计数增加后: " << sharedPtr.use_count() << std::endl;
} // anotherPtr 超出作用域,引用计数减少
// 输出引用计数
std::cout << "引用计数减少后: " << sharedPtr.use_count() << std::endl;
return 0;
}
- 可能存在循环引用的问题:当两个或多个对象之间相互持有 std::shared_ptr,可能会导致循环引用,从而导致资源无法释放,产生内存泄漏。
#include <memory>
class A;
class B;
class A {
public:
std::shared_ptr<B> bPtr;
};
class B {
public:
std::shared_ptr<A> aPtr;
};
int main() {
std::shared_ptr<A> aPtr(new A);
std::shared_ptr<B> bPtr(new B);
// 循环引用,导致资源无法释放
aPtr->bPtr = bPtr;
bPtr->aPtr = aPtr;
return 0;
}
std::weak_ptr
std::weak_ptr 是一种弱引用智能指针,它不会增加资源的引用计数。
主要用于解决 std::shared_ptr 的循环引用问题,避免因循环引用导致的内存泄漏。
std::weak_ptr 不能直接访问资源,需要通过调用 lock() 方法获取一个指向资源的 std::shared_ptr,然后才能访问资源。
下面演示了如何使用 std::weak_ptr 解决循环引用问题:
#include <memory>
#include <iostream>
class B; // 前置声明
class A {
public:
std::weak_ptr<B> bWeakPtr; // 使用 weak_ptr 避免循环引用
};
class B {
public:
std::shared_ptr<A> aSharedPtr;
};
int main() {
// 创建 shared_ptr 对象
std::shared_ptr<A> aSharedPtr(new A);
std::shared_ptr<B> bSharedPtr(new B);
// 使用 weak_ptr 避免循环引用
aSharedPtr->bWeakPtr = bSharedPtr;
bSharedPtr->aSharedPtr = aSharedPtr;
// 通过 lock() 方法获取 shared_ptr,然后访问资源
if (auto sharedPtr = aSharedPtr->bWeakPtr.lock()) {
// 访问资源
}
return 0;
}
通过将其中一个指针声明为 std::weak_ptr,可以防止循环引用。然后,可以通过调用 lock() 方法获取一个指向资源的 std::shared_ptr,然后使用该 shared_ptr 访问资源。