您的位置:首页 > 其它

智能指针(一)

2016-09-04 15:36 429 查看
动态内存与智能指针

在C++中,动态内存的管理是通过一对运算符来完成的。new在动态内存中为对象 分配空间并且返回一个指向该类对象的指针。delete接受一个动态对象的指针,销毁该对象,并释放与之关联的内存。
动态内存的使用很容易出现问题,因为确保正确的时间释放内存是极其困难的。有时我们会忘记释放内存,导致内存泄漏。
为了更容易(或者说是为了安全)地使用动态内存,我们提出了智能指针。(个人人觉得智能指针特别方便,它把内存管理封装在一个类里面,而类自己就可以完成对象的销毁,省得自己去操心)


为什么使用智能指针

直接看代码,一目了然

void Test2()
{
int* p1 = new int(2);
bool isEnd = true;

//...
if (isEnd)
{
//delete p1;//这里要小心
return;
}
//...

delete p1;
}
/////////////////////////////////////////////////
void DoSomeThing()
{
//...
throw 2;
//...
}

void Test2()
{
int* p1 = new int(2);

//...
try {
DoSomeThing();
}
catch (...)
{
//delete p1;//抛出异常要在这里delete否则出现野指针
throw;
}
//...

delete p1;
}




引入智能指针

定义一个类来封装资源的分配和释放,在构造函数完成资源的分配和初始化,在析构函数完成资源的清理,可以保证资源的正确初始化和释放。

1.auto_ptr,这个其实是一个坑货

看代码:

template<class T>
class AutoPtr
{
public:
AutoPtr( T* ptr)
:_ptr(ptr)
{}
AutoPtr(AutoPtr<T>& s) //里面不能用const
:_ptr(s._ptr)
{
s._ptr = NULL;
}

AutoPtr& operator=(AutoPtr<T>& s)
{
if (s._ptr != _ptr)
{
delete _ptr;
_ptr = s._ptr;
s._ptr = NULL;
}
return *this;
}

~AutoPtr()
{
if (_ptr)
delete _ptr;
}

T& operator*()
{
return *_ptr;
}
private:
T* _ptr;
};

//存在问题

AutoPtr<int> ap1 = new int(1);
AutoPtr<int> ap2(ap1);
AutoPtr<int> ap3(ap2);
*ap1 = 10;//直接崩溃了


虽然上面的auto_ptr解决了内存管理问题,你不用在担心什么时候去释放那个空间。但是在拷贝构造和运算符重载时,我们很尴尬。每拷贝一个对象就要释放前面的那个对象,那么我们在后面想访问前面定义那个对象岂不是会出现问题。本来是为了解决内存问题,现在又在拷贝构造出现问题。

2.scoped_ptr 防拷贝简单暴力

对比上面的auto_ptr,会出现拷贝问题,我们把拷贝构造和赋值运算符声明为private这样外面的东西就不能访问这个成员函数了。这样就是简单暴力的求解方法

private:
ScopePtr(const ScopePtr& sp);

ScopePtr<T>& operator=(const ScopePtr& sp);


3.为了解决上面问题,引入shared_ptr,在这个类里面引用引用计数,和string一样,计数拷贝次数,当拷贝计数只有一次的话,就可以析构这个东西了。

template <class T>
class SharePtr
{
public:
SharePtr( T* ptr)
:_ptr(ptr)
, _pCount(new int(1))
{}

~SharePtr()
{
if (--(*_pCount) == 0)
{
delete _pCount;
delete _ptr;
}
}

SharePtr(SharePtr<T>& s)
:_ptr(s._ptr)
, _pCount(s._pCount)
{
++*_pCount;
}

SharePtr<T>& operator=(SharePtr<T>& s)
{
if (this != &s)
{
if ( --(*_pCount) == 0 )//这里解决了一个问题,在下面说
{
delete _ptr;
delete _pCount;
}

_ptr = s._ptr;
_pCount = s._pCount;
++(*_pCount);

}
return *this;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
private:
int *_pCount;
T    *_ptr;
};

用test来测试上面代码
void Test()
{
SharePtr<int> s1 = new int(10);
SharePtr<int> s2(s1);

SharePtr<int> s3 = new int(20);
s2 = s3;//这块很容易出问题
}


对上面问题的解释:



所以上面那个拷贝构造的时候,解决了这个问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: