c++之我们为什么选择使用智能指针

如题所述

你的内存管理原则是否正确?
学C++的同学都知道这个内存管理原则,就是“谁创建,谁释放”或者说“谁申请,谁释放”。简单地说,在代码上体现为,调用new或malloc等内存分配的人,同时需在内存使用完成后调用delete或free释放。
这个原则看似大家都同意,毕竟只有申请内存的人,才知道什么时候该释放内存。
这无疑是一个正确的原则,但这个原则在任意场景中是否都合理呢,不见得。按照这个原则,作为一个接口提供者,要保证自己没有内存问题,其实很简单,接口提供者只需把内存申请和释放的工作都交给接口使用者就可以了。这看似很完美,我不创建,就不需要释放,也就不存在内存漏洞的问题,如果系统有内存泄露的问题,那肯定是接口使用者的责任。不知道真相的使用者只能“满眼泪光”地回去调逻辑,知道真相的使用者也只能无辜地回去调代码。
接口提供者是否做好了?
接口设计者做对了,但不一定是做好了,或者说,接口设计者不一定做得够好了。
在我们评论接口设计者做得是否“够好了”之前,我们首先得确立一个简单评价的标准。
按照个人观察(并非独创想法),通俗总结,一个好的接口设计有如下特点:
1、满足使用者功能要求(当然是基础);
2、接口友好,容易理解和使用;
3、容易被正确使用(第二点的延伸);
4、……
按照以上标准看,作为接口使用者的我们来看,接口设计者似乎的确做得不够好,因为他总是把容易出错的部分交给接口使用者来完善,增加了接口使用者设计上的难度。不满足以上标准的第2、3点。
智能指针的作用在哪里?
OK,我们终于涉及智能指针了,在这里我们不打算讲智能指针的实现原理,这部分网上有很多可以参考的文章,另外,这部分也不需要大家去实现,现在c++11已经有标准的智能指针形式std:share_ptr,这意味着你想使用智能指针,是一件非常容易的事情。
使用智能指针,能让接口设计者做得更好:
智能指针的作用在于能自动释放指针,减少人为使用new和delete所存在的内存问题。接口设计者可以运用智能指针,把申请内存的工作都在接口内部实现并加以限制,把释放内存的工作交给智能指针。
常见的形式如下代码,接口提供者提供私有构造函数类,禁止外部直接创建,而接口使用者可以通过使用类的CreateInstance获得一个Test类对象。
这样,接口使用者不需要在关注内存释放问题。根据如下代码的形式,我们总结下只能指针的优点:
1、由于CreateInstance返回一个Test类型的智能指针对象,由智能指针负责释放。
2、接口使用者没有直接调用new申请内存故也无需调用delete释放。
3、接口设计设把类构造函数设为私有(我们在此不考虑这样做的拓展性方面的影响),限制外面使用new创建,接口友好度提高,而且更加容易被正确使用。
class Test
{
public:
typedef std::shared_ptr<Test> TestPtr
static TestPtr CreateInstance()
{
return new Test();
}
private:
Test()
{
}
};
温馨提示:答案为网友推荐,仅供参考
第1个回答  2020-02-18
栈上开辟的能自动释放, 会自动调用 构造函数和析构函数、
堆上开辟的不能自动释放,需要手动delete。
智能指针,就是弄出来一个指针,在堆上开辟的指针,但 不需要手动释放的指针。
例如
有个类 class Perosn的类,类里面有个成员m_Age,通过有参构造初始化。
堆上开辟 Person*p=new Perosn(10) 那么,这就在堆上开辟了,m_Age是10;
这样的话,到最后,一定要手动 delete p; 需要手动释放。
为了避免忘记释放,就要搞一个智能指针,代替 Person的指针p

再建立一个类比如 class smartPointer ,
把Person 中的指针p, 通过有参构造的方法传到 smartpointer里面
smartPointer(Person*p)
{
this->p =p;
}
然后内部自己维护一个 成员变量名字叫
Perosn*p ,
然后再弄一个析构函数,
里面判断, if(p!=NULL)
{
delete p;
P->NULL;
}

这样就初步完成了智能指针, 仅仅解决了释放的问题。
通过栈的自动释放,把堆的里面顺便给释放了, 也就不需要手动释放了。
比如

smartPointer sp(new Person*p)
栈上开辟了一个sp, 传进来一个有参 ,(参数是堆上开辟的指针)
为了使 sp 能够像p 一个 ,调用Person类里面的 m_Age;
比如
p->m_Age ; (*p).m_Age; 正常可用
sp->m_Age ; (*sp).mAge; 报错,不过希望达到这样的效果
那么久需要在smartpointer的类里面重载符号->和*
具体代码
Person* operator->()
{
return this->p;
}

Person & operator*()
{
retrun * this->p
}
这样,指针 sp 就能像p 一样使用了, 也不必考虑释放的问题。很方便。
相似回答