44 C++智能指针详解:安全高效管理内存
目录
一. 智能指针简介
智能指针是用于解决传统指针的内存泄漏问题,智能可以可以自动释放开辟的资源。还能用于解决共享所有权指针的释放问题(比如多个指针指向同一个对象进行释放问题)
注:
智能指针本身是线程安全的,但是管理的对象不一定是线程安全的
智能指针的原理是RAII,构造时候开辟,析构时候释放。下篇文章会详细说明
C++中使用智能指针需要包含头文件memroy并且只有c++11以上版本支持
二. 共享智能指针 shared_ptr
shared_ptr是共享智能指针,即可以多个指针管理同一个对象。
2.1 初始化
shared_ptr可以通过构造函数,拷贝构造,make_shared函数三种方式初始化。代码如下
#include <iostream>
#include <memory>
#include <string>
int main()
{
// 构造函数初始化
std::shared_ptr<std::string> ps1(new std::string("Hello World!"));
// 拷贝构造,这里使用匿名对象进行拷贝。
std::shared_ptr<std::string> ps2 = std::shared_ptr<std::string>(new std::string("Hello World!"));
// make_shared 这个使用比较方便,推荐使用
// make_shared可以不用传入指针,直接传值即可自动构造智能指针
auto ps3 = std::make_shared<std::string>("Hello World!");
std::cout << "ps1:" << *ps1 << std::endl;
std::cout << "ps2:" << *ps2 << std::endl;
std::cout << "ps3:" << *ps3 << std::endl;
return 0;
}

一般都推荐使用 make_shared。效率和安全性比较高
2.2 shared_ptr相关操作
get函数,可以通过get这个函数获取shared_ptr管理对象的裸指针。但是不建议使用这个操作
reset:用于重置shared_ptr
假如有一个shared_ptr P:
如果P使用的reset且不带参数的P.reset(),此时shared_ptr的引用计数会减一,并且将P置空。如果引用计数-1之后为0,此时会销毁这个对象
如果P是带参数的(P.reset(otherP)),如果P是这个对象的唯一智能指针,此时会释放这个对象,并且指向新的对象。反之,P对象的智能指针的引用计数-1,然后指向新对象
2.3 shared_ptr使用注意与循环引用问题
1 不要在函数参数中构建智能指针
2 不能同时将一个裸指针托管给两个智能指针,这样会导致析构异常(shared_ptr的共享的实现需要通过 拷贝和赋值来实现)
3 在类的内部,不要使用this指针作为共享指针的右值返回,与第二条一样,这样会导致this指针被两个即以上的智能指针管理并且每一个控制块不一样!需要使用
shared_from_this()来解决这个问题
另外,还需要注意智能指针的循环引用问题!假如有这样两个类
class A
{
public:
shared_ptr<B> a;
};
class B
{
public:
shared_ptr<A> a;
};
A中哦有B的智能指针,B中有A的智能指针。他们相互包含
此时如果我们创建了一个A对象,一个B对象。如果我们分别创建两个智能指针sp1,sp2分别管理两个对象那么他们的结构如下
此时A对象shared_ptr和B对象的shared_ptr的引用计数都是2
当程序结束时候,sp1和sp2就会销毁,各自引用计数-1,引用计数变为1。
引用计数不为0,两个对象都不会销毁
此时结构如下
然后b指针想要销毁,必须要先销毁A对象,即销毁a指针
而销毁a指针的时候又要先销毁B对象,即销毁b指针。
结果就是我销毁的前提是我被销毁了。这样导致死循环。这种问题就是循环引用问题
解决循环引用问题可以使用weak_ptr(弱引用智能指针)
三. 弱引用智能指针weak_ptr
weak_ptr它只是用于解决shared_ptr的循环引用问题。
原理是:weak_ptr只观察对象,不会增加引用计数。在上面例子中,如果使用weak_ptr。
class A { public: weak_ptr<B> a; }; class B { public: weak_ptr<A> a; };当两个对象创建的时候,引用计数为1(weak_ptr不会增加引用计数)
但销毁的时候,引用计数-1。
此时引用计数为0,两个对象都销毁了。
因此weak_ptr可以打破shared_ptr的循环引用。
四. auto_ptr 和 unique_ptr
4.1 auto_ptr
auto_ptr是早版本的智能指针,它通过转移管理权来实现功能。但是这样会导致原先的指针在转移之后会被置空。
那么原先的指针就无法使用了,并且会有空指针解引用问题出现,所以这个智能指针引进被废弃了。
4.2 unique_ptr
unique_ptr是独占指针,无法被拷贝。可以理解为无法拷贝的shared_ptr。由于无法被拷贝,就不会出现多个指针指向同一个对象的而导致多次销毁问题。
unique_ptr的使用方式与shared_ptr非常类似
代码如下:
更多推荐





所有评论(0)