一、智能指针
用于解决原始指针使用不当经常出现的内存泄漏问题;
项目中实例:
std::shared_ptr<ObstructionResult> pResult = std::make_shared<ObstructionResult>();
pResult->Width = rw;
pResult->Height = rh;
pResult ->Dist = d;
pResult->ImageWidth = 1920 ;
pResult->ImageHeight = 1080;
pResult->ImageNO = 0; //帧号默认为0
pResult->ImageDataLen = 1920*1080*3;
memcpy(pResult->pImageData, tmp, pResult->ImageDataLen);
if(nullptr != CAlarmManager::instance)
{
CAlarmManager::instance()->reportObstacleAlarm(pResult);
}
在视频流处理中,经常遇到的业务场景是相机传回一帧图像数据时,需要申请个内存来保存这帧数据,此处进行了指针的创建,之后该数据需要传递到下一个业务模块中,此时就需要考虑该内存空间释放的问题,是在本模块释放,还是在下一个模块释放,如果数据需要依次传递给多个模块,则空间的释放问题就特别复杂,要考虑正常情况下那个模块释放,异常情况下那个模块释放的问题,在考虑不周时还容易引起内存泄漏,此处之前的做法是:
1、指针传入模块时,模块内部重新申请内存,模块内部申请的内存,模块内部释放,但是这样降低了程序的效率,导致程序频繁的申请内存,容易造成内存碎片;
2、各个模块共用一个指针,指针在使用完成后,由创建者释放,这样提高了效率,但是如果指针的释放逻辑要考虑较多条件,增加不必要麻烦,特别对于各个模块如果不是顺序执行的话,逻辑盖更加复杂;
3、接着出现了引用计数的方法,原理是每个模块使用完成都进行释放,但是真正的释放是在最后一个模块使用完成,C++标准库中推出的实现该机制的就是shared_ptr;
二、使用过程中需要考虑的问题
shared_ptr在使用中需要注意循环引用,循环引用会导致堆内存无法正确释放。
如下代码中pA和pB之间循环引用,导致无法正常析构对象,运行程序,无析构函数的执行打印。
class Child;
class Parent;
class Parent
{
public:
virtual ~Parent() { std::cout << "delete Parent " << std::endl; };
public:
std::shared_ptr<Child> child;
};
class Child
{
public:
virtual ~Child() { std::cout << "delete Child " << std::endl; };
public:
std::shared_ptr<Parent> parent;
};
int main()
{
{
std::shared_ptr<Parent> pA(new Parent);
std::shared_ptr<Child> pB(new Child);
pA->child = pB;
pB->parent = pA;
}
system("pause");
}
为了解决循环引用问题,引入了weak_ptr,weak_ptr指向shared_ptr指针指向的对象的内存,却并不拥有该内存,可以打破循环引用;
C++11学习之share_ptr和weak_ptr_编程实战营的博客-CSDN博客_shared_ptr weak_ptr
C++智能指针详解:shared_ptr_吃素的施子的博客-CSDN博客_c++ shared_ptr
三、shared_ptr多线程安全性
1、多线程操作shared_ptr引用计数,线程安全(原子操作)
2、多线程操作的是同一个shared_ptr的对象指向,非线程安全的
3、多线程操作的不是同一个shared_ptr的对象指向,线程安全的
4、多线程操作shared_ptr的对象所管理数据,非线程安全的
四、unique_ptr
定义: 独享被管理对象指针所有权的智能指针,因此,我们无法通过复制构造函数或赋值运算符创建unique_ptr对象的副本,在使用使用过程中可以根据业务逻辑来用unique_ptr来管理有确定占用关系的对象,而不是使用原始的指针,这样对该资源起到一定的保护作用。