引入
裸指针是C++中最基本的指针类型。它们直接存储内存地址,并允许通过指针访问和操作内存中的数据
然而,手动管理指针会带来复杂性和潜在的错误 内存泄漏、悬空指针和双重释放等问题会导致程序崩溃或产生难以排查的错误
C++11引入的智能指针旨在解决这些问题。智能指针的本质就是封装的裸指针,自动管理对象的生命周期,从而减少手动内存管理带来的风险
在C++标准库中提供了三种主要的智能指针:std::unique_ptr
、std::shared_ptr
和 std::weak_ptr
1.std::unique_ptr 独占指针
std::unique_ptr
是一种独占所有权的智能指针,一个std::unique_ptr
只能独占其所指向的对象,同一时间只有一个指针拥有该对象。当 std::unique_ptr
被销毁时,它所管理的对象也会被自动销毁。std::unique_ptr
不支持复制操作,但支持移动操作,这使得它非常适合用于管理动态分配的资源
具体操作:
创建:使用std::make_unique
访问:使用*ptr或者ptr.get()获取原始指针访问
转移所有权:使用std::move
代码演示:
#include <iostream>
#include <memory>//引入智能指针的头文件
int main(void) {
std::unique_ptr<int> ptr1(new int(10)); // 创建一个指向整数10的unique_ptr
std::cout << "ptr1 的值: " << *ptr1 << std::endl;
// std::unique_ptr<int> ptr2 = ptr1; // 错误:unique_ptr不能被拷贝
std::unique_ptr<int> ptr2 = std::move(ptr1); // 正确:通过std::move进行所有权转移
if(ptr1 == nullptr) {
std::cout << "ptr1 为空" << std::endl;
}
std::cout << "ptr2 的值: " << *ptr2 << std::endl;//打印10
}
2.std::shared_ptr共享指针
std::shared_ptr
是一种共享所有权的智能指针,多个std::shared_ptr
可以共享同一个对象。通过引用计数来管理对象的生命周期,当最后一个指向该对象的shared_ptr
被销毁时,该对象才会被销毁。
具体操作:
创建:使用std::make_shared
访问:使用*ptr或者ptr.get()获取原始指针访问
引用计数:使用use_count
方法
代码演示:
#include <iostream>
#include <memory>//引入智能指针头文件
int main(void) {
std::shared_ptr<int> ptr1(new int(10)); // 创建一个指向整数10的shared_ptr
std::cout << "ptr1 的值: " << *ptr1 << std::endl;
std::shared_ptr<int> ptr2 = ptr1; // 可复制 ptr2与ptr1共享同一个对象
std::cout << "ptr2 的值: " << *ptr2 << std::endl;
std::cout << "ptr1 的引用计数: " << ptr1.use_count() << std::endl;
std::cout << "ptr2 的引用计数: " << ptr2.use_count() << std::endl;//都是2
}
3.std::weak_ptr小帮手
std::weak_ptr
是一种弱引用智能指针,它不会影响对象的引用计数,专门用来于解决std::shared_ptr
之间的循环引用问题 。所以std::weak_ptr
必须与std::shared_ptr
一起使用
什么是循环引用?
两个共享指针相互指向对方 导致引用计数无法归0 最终导致程序崩溃
代码示例:
#include <iostream>
#include <memory>
class B;
class A {
public:
std::shared_ptr<B> ptrB;
};
class B {
public:
std::shared_ptr<A> ptrA;
};
int main(void) {
{
std::shared_ptr<A> a = std::make_shared<A>();
std::shared_ptr<B> b = std::make_shared<B>();
a->ptrB = b;
b->ptrA = a;
}
}
所以为了解决这个问题专门引入的weak_ptr
将class A和class B中的任意一个shared_ptr改成weak_ptr即可解决
#include <iostream>
#include <memory>
class B;
class A {
public:
std::shared_ptr<B> ptrB;
};
class B {
public:
std::weak_ptr<A> ptrA; // 使用 weak_ptr 来避免循环引用
};
int main() {
{
std::shared_ptr<A> a = std::make_shared<A>();
std::shared_ptr<B> b = std::make_shared<B>();
a->ptrB = b;
b->ptrA = a;
// a 和 b 的引用计数会开始减少。
// 由于 B 类中使用的是 weak_ptr,所以不会阻止 A 类对象的释放。
}
// 在此处,a 和 b 都会被正确释放,不再存在循环引用。
}
总结
为了避免忘记释放内存导致一系列的问题 智能指针能用则用
这篇文章讲的只是智能指针皮毛中的皮毛,智能指针还有很多内置函数没有提到,有兴趣可以通过其他途径了解更多相关知识