new对象的缺陷
int div()
{
int a, b;
cin >> a >> b;
if (b == 0)
throw invalid_argument("除0错误");
return a / b;
}
void Func()
{
int* p1 = new int;
int* p2 = new int;
cout << div() << endl;
delete p1;
delete p2;
}
int main()
{
try
{
Func();
}
catch (exception& e)
{
cout << e.what() << endl;
}
return 0;
}
在这段代码中,如果new p2 或者 div()报异常时,就不会执行到 delete ,造成内存泄漏 因此为了解决这种问题,就有人了想出智能指针
智能指针的使用
智能指针分为三类:unique_ptr , shared_ptr weak_ptr
unique_ptr
unique_ptr的实现原理:简单粗暴的防拷贝 使用
unique_ptr<int> up(new int);
模拟实现
template<class T>
struct default_delete
{
void operator()(const T* ptr)
{
delete ptr;
}
};
template<class T,class Del= default_delete<T>>
class unique_ptr
{
public:
unique_ptr(T* ptr)
:_ptr(ptr)
{}
unique_ptr(const unique_ptr& uptr) = delete;
unique_ptr& operator=(const unique_ptr& uptr) = delete;
~unique_ptr()
{
Del del;
del (_ptr);
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
private:
T* _ptr;
};
shared_ptr
shared_ptr的原理:是通过引用计数的方式来实现多个shared_ptr对象之间共享资源。
-
shared_ptr在其内部,给每个资源都维护了着一份计数,用来记录该份资源被几个对象共 享。 -
在对象被销毁时(也就是析构函数调用),就说明自己不使用该资源了,对象的引用计数减1。 -
如果引用计数是0,就说明自己是最后一个使用该资源的对象,必须释放该资源; -
如果不是0,就说明除了自己还有其他对象在使用该份资源,不能释放该资源,否则其他对 象就成野指针了。
使用
shared_ptr<int> sp(new int);
模拟实现
template<class T, class Del = default_delete<T>>
class shared_ptr
{
public:
shared_ptr(T* ptr)
:_ptr(ptr)
{
_count = new int(1);
}
shared_ptr(const shared_ptr& sptr)
{
_ptr = sptr._ptr ;
_count = sptr._count;
(*_count)++;
}
const shared_ptr& operator=(const shared_ptr& sptr)
{
if (sptr._ptr != _ptr)
{
Release();
_ptr = sptr._ptr;
_count = sptr._count;
(*_count)++;
}
return *this;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
~shared_ptr()
{
Release();
}
private:
void Release()
{
(*_count)--;
if (*_count == 0)
{
Del del;
del(_ptr);
}
}
int* _count;
T* _ptr;
};
weak_ptr
struct ListNode
{
ListNode()
:_next(nullptr)
,_prev(nullptr)
{}
~ListNode()
{
cout << "~ListNode()" << endl;
}
zjq::shared_ptr<ListNode> _next;
zjq::shared_ptr<ListNode> _prev;
};
void test_shared2()
{
zjq::shared_ptr<ListNode> sp1(new ListNode);
zjq::shared_ptr<ListNode> sp2(new ListNode);
sp1->_next = sp2;
sp2->_prev = sp1;
}
在上述场景中,当函数调用完后之后调用sp1和sp2的析构函数,但count还未到0,无法释放, 因此引入weak_ptr;
使用
shared_ptr<int> sp(new int);
weak_ptr<int> wk(sp);
实现原理
template<class T>
class weak_ptr
{
public:
weak_ptr()
:_ptr(nullptr)
{}
weak_ptr(const shared_ptr<T>& sp)
:_ptr(sp.get())
{}
weak_ptr<T>& operator=(const shared_ptr<T>& sp)
{
if (_ptr != sp.get())
{
_ptr = sp.get();
}
return *this;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
public:
T* _ptr;
};
|