问题引入
int func1(int x)
{
int y = 10;
int* tmp = (int*)malloc(sizeof(int) * 2);
if (x == 0)
throw "func1_error";
else
return x + y;
free(tmp);//抛异常造成异常安全问题,无法释放造成内存泄漏,
}
int main()
{
try { int a=func1(0); }
catch (const char* error)
{
cout << error << endl;
}
return 0;
}
智能指针的使用及原理
RAII(面试官喜欢问)
使用RAII思想设计的Smart_sptr类
template<class T>
class Smart_sptr
{
public:
Smart_sptr(T* sptr=nullptr)
:_ptr(sptr)
{}
~Smart_sptr()
{
if (_ptr)
{
delete _ptr;
cout << "~Smart_sptr" << endl;
}
}
T& operator*() { return *_ptr; }
T* operator->() { return _ptr; }
private:
T* _ptr;
};
struct Date
{
int _year;
int _month;
int _day;
};
int main()
{
//实现指针操作
Smart_sptr<int> sp1(new int);
*sp1 = 10;
cout << *sp1 << endl;
//管理资源
Smart_sptr<Date> sp2(new Date);
// 需要注意的是这里应该是sparray.operator->()->_year = 2018;
// 本来应该是sparray->->_year这里语法上为了可读性,省略了一个->
sp2->_year = 2018;
sp2->_month = 1;
sp2->_day = 1;
cout << sp2->_year << " " << sp2->_month << " " << sp2->_day << endl;
//测试生命周期
cout << (*(Smart_sptr<int>(new int)) = 11) << endl;
//执行完后立马析构,资源释放
return 0;
}
std::auto_ptr
C++98版本的库中就提供了auto_ptr的智能指针。
#include <memory>
class Date
{
public:
Date() { cout << "Date()" << endl; }
~Date() { cout << "~Date()" << endl; }
int _year;
int _month;
int _day;
};
int main()
{
auto_ptr<Date> ap(new Date);
auto_ptr<Date> copy(ap);
// auto_ptr的问题:当对象拷贝或者赋值后,前面的对象就悬空了copy()括号内的内容悬空
// C++98中设计的auto_ptr问题是非常明显的,所以实际中很多公司明确规定了不能使用auto_ptr
ap->_year = 2018;
return 0;
}
std::unique_ptr
int main()
{
unique_ptr<Date> up(new Date);
// unique_ptr的设计思路非常的粗暴-防拷贝,也就是不让拷贝和赋值。
unique_ptr<Date> copy(ap);
return 0;
}
std::shared_ptr
简单样例
struct Date
{
int _year;
int _month;
int _day;
};
int main()
{
// shared_ptr通过引用计数支持智能指针对象的拷贝
shared_ptr<Date> sp(new Date);
//use_count()返回引用计数个数
cout << "第一个对象sp管理new Date的引用计数:" << sp.use_count() << endl;
shared_ptr<Date> copy(sp);
cout << "新增一个对象后sp的引用计数:" << sp.use_count() << endl;
cout << "第二个对象copy管理new Date的引用计数:" << copy.use_count() << endl;
return 0;
}
图解
shared_ptr的原理:
模拟实现Shared_Ptr
初级版本
#include<string>
template<class T>
class Shared_Ptr
{
public:
//构造
Shared_Ptr(T* ptr = nullptr)
:_ptr(ptr)
, _pcount(new int(1))//数组,开始初始化赋值为1
{}
//析构函数
~Shared_Ptr()
{
//初始版本
//if (_pcount == 0)
//{
// delete _pcount;
// delete _ptr;
//}
//else
//{
// --_pcount;
//}
//保证赋值重载能调用析构
release();
}
//拷贝构造
Shared_Ptr(const Shared_Ptr<T>& sp)
:_ptr(sp._ptr)
,_pcount(sp._pcount)
{
++(*_pcount);//拷贝后多一个对象管理,引用计数+1
}
//实现智能指针
T& operator*() { return *_ptr; }
T* operator->() { return _ptr; }
//获得引用计数个数
int use_count() { return *_pcount; }
//返回类中原式指针
T* get() { return _ptr; }
void release()
{
//当引用计数为1时,不再让该指针管理资源,应该立马释放
//如果是下面这样,当引用计数为1时,只让引用计数-1并没有释放
//正常情况下引用计数为1时在调用release时就应该delete了
//if (*_pcount != 0)或者改成!=1
//{
// --(*_pcount);
//}
//else
//{
// delete _pcount;
// delete _ptr;
//}
if (--(*_pcount) == 0)
{
delete _pcount;
delete _ptr;
}
}
//赋值重载--遇见想要多个对象管理时sp1=sp2
Shared_Ptr<T>& operator=(const Shared_Ptr<T>& sp)
{
//两种情况--1.自己赋值,2.两个不同的赋值
if (sp._ptr!= _ptr)//不同
{
//释放sp1所管理的内容or减去sp1所管理内容的引用计数
//从引用计数上保证sp1不在管理该块内容
//调用析构,多套一层release函数
release();
_ptr = sp._ptr;
_pcount = sp._pcount;
++(*_pcount);
}
//else
//{
// return *this;
// //相同返回对象本身
//}
全部完成后返回对象本身
//return *this;
//上述两个return可以合并成一个,在执行完不同对象的赋值后需要返回*this
//相同时不进入if也返回*this
return *this;
}
private:
int* _pcount;//引用计数个数
T* _ptr;//管理指针
};
int main()
{
Shared_Ptr<string> sp1(new string("test_smart_pointer"));
Shared_Ptr<string> sp2(sp1);//测试拷贝
cout << "sp1:" << sp1.get() << " _pcount " << sp1.use_count() << endl;//use_count()显示总引用计数
cout << "sp2:" << sp2.get() << " _pcount " << sp2.use_count() << endl;
cout << endl;
Shared_Ptr<string> sp3(new string("test_assignment"));
sp3 = sp3;//相同赋值
cout << "sp3:" << sp3.get() << " _pcount " << sp3.use_count() << endl;
sp1 = sp3;//不同赋值
cout << "sp1:" << sp1.get() << " _pcount " << sp1.use_count() << endl;
cout << "sp2:" << sp2.get() << " _pcount " << sp2.use_count() << endl;
cout << "sp3:" << sp3.get() << " _pcount " << sp3.use_count() << endl;
return 0;
}
结果:
升级
原代码测试
// 仿函数的删除器
template<class T>
struct FreeFunc {
void operator()(T* ptr)
{
cout << "free:" << ptr << endl;
free(ptr);
}
};
template<class T>
struct DeleteArrayFunc {
void operator()(T* ptr)
{
cout << "delete[]" << ptr << endl;
delete[] ptr;
}
};
int main()
{
FreeFunc<int> freeFunc;
shared_ptr<int> sp1((int*)malloc(4), freeFunc);
DeleteArrayFunc<int> deleteArrayFunc;
shared_ptr<int> sp2((int*)malloc(4), deleteArrayFunc);
return 0;
}
改造模拟实现代码
重载调用不明确
缺陷
Shared_Ptr<ListNode> sp4(new ListNode[10], DelArray<ListNode>());
Shared_Ptr<ListNode> sp5(new ListNode[10], [](ListNode* ptr) {delete[] ptr; });
sp4->next=sp5;
sp5->prev=sp4;