1.scoped_array以及unique_ptr unique_ptr的实现原理:简单粗暴的防拷贝
#include<iostream>
#include<boost/smart_ptr.hpp>
using namespace std;
using namespace boost;
void test01()
{
int* ptr = new int[10]{ 1,2,3,4,5,6,7,8,9,10 };
scoped_array<int> sa(ptr);
for (int i = 0; i < 10; ++i)
cout << sa[i] << " ";
cout << endl;
}
void test02()
{
int* ptr = new int(10);
unique_ptr<int> up(ptr);
cout << *up << endl;
//unique_ptr<int> up1 = up;//不能赋值也不能拷贝构造
}
void main()
{
test02();
}
2.shared_ptr:所有权共享,使用引用计数,减到零才释放空间
#include<iostream>
#include<boost/smart_ptr.hpp>
//#include<boost/shared_ptr.hpp>
using namespace std;
//using namespace boost;
void test01()
{
int* ptr = new int(10);
shared_ptr<int> sp(ptr);
cout << *sp << endl;
cout << "use count" << sp.use_count() << endl;
{
shared_ptr<int> sp1;
sp1 = sp;
cout << "use count" << sp1.use_count() << endl;
}
shared_ptr<int> sp2 = sp;
cout << "use count" << sp2.use_count() << endl;
}
void main()
{
test01();
}
3.shared_ptr模拟实现
shared_ptr
的原理:是通过引用计数的方式来实现多个
shared_ptr
对象之间共享资源
。
1. shared_ptr
在其内部,
给每个资源都维护了着一份计数,用来记录该份资源被几个对象共享
。
2.
在
对象被销毁时
(
也就是析构函数调用
)
,就说明自己不使用该资源了,对象的引用计数减一。
3.
如果引用计数是
0
,就说明自己是最后一个使用该资源的对象,
必须释放该资源
;
4.
如果不是
0
,就说明除了自己还有其他对象在使用该份资源,
不能释放该资源
,否则其他对象就成野指
针了。
shared_count.h
#pragma once
#include"sysutil.h"
#include"sp_counted_base.h"
#include"sp_counted_impl.h"
template<class Type>
class shared_count
{
public:
template<class Y >
shared_count(Y* p):pi_(new sp_counted_impl<Y>(p))
{
#ifdef DISPLAY
std::cout << "Create SHARED_COUNT" << std::endl;
#endif
}
shared_count(const shared_count<Type>& r) :pi_(r.pi_)
{
if (pi_)
pi_->add_ref_copy();
}
void swap(shared_count& r)
{
sp_counted_base* tmp = r.pi_;
r.pi_ = pi_;
pi_ = tmp;
}
~shared_count()
{
#ifdef DISPLAY
std::cout << "Free SHARED_COUNT" << std::endl;
#endif
if (pi_ != NULL)
{
pi_->release();
}
}
long use_count()const
{
return pi_->use_count();
}
private:
sp_counted_base* pi_;
};
shared_ptr.h
#pragma once
#include"sysutil.h"
#include"shared_count.h"
template<class Type>
class shared_ptr
{
public:
typedef shared_ptr<Type> this_type;
public:
shared_ptr(Type* p):pn(p),px(p)
{
#ifdef DISPLAY
std::cout << "Create SHARED_PTR" << std::endl;
#endif
}
shared_ptr(const shared_ptr<Type>& r):px(r.px),pn(r.pn)
{}
this_type& operator=(const this_type& r)
{
this_type(r).swap(*this);
return *this;
}
Type& operator*()
{
return *px;
}
Type* operator->()
{
return px;
}
~shared_ptr()
{
#ifdef DISPLAY
std::cout << "Free SHARED_PTR" << std::endl;
#endif
}
long use_count()const
{
return pn.use_count();
}
void swap(shared_ptr<Type>& other)
{
std::swap(px, other.px);
pn.swap(other.pn);
}
private:
Type* px;
shared_count<Type> pn;
};
sp_counted_base.h
#pragma once
#include"sysutil.h"
#include"shared_count.h"
template<class Type>
class shared_ptr
{
public:
typedef shared_ptr<Type> this_type;
public:
shared_ptr(Type* p):pn(p),px(p)
{
#ifdef DISPLAY
std::cout << "Create SHARED_PTR" << std::endl;
#endif
}
shared_ptr(const shared_ptr<Type>& r):px(r.px),pn(r.pn)
{}
this_type& operator=(const this_type& r)
{
this_type(r).swap(*this);
return *this;
}
Type& operator*()
{
return *px;
}
Type* operator->()
{
return px;
}
~shared_ptr()
{
#ifdef DISPLAY
std::cout << "Free SHARED_PTR" << std::endl;
#endif
}
long use_count()const
{
return pn.use_count();
}
void swap(shared_ptr<Type>& other)
{
std::swap(px, other.px);
pn.swap(other.pn);
}
private:
Type* px;
shared_count<Type> pn;
};
sp_counted_impl.h
#pragma once
#include"sysutil.h"
#include"sp_counted_base.h"
template<class X>
class sp_counted_impl:public sp_counted_base
{
public:
sp_counted_impl(X* px) :px_(px)
{
#ifdef DISPLAY
std::cout << "create SP_COUNTED_IMPL" << std::endl;
#endif
}
void dispose()
{
delete px_;
}
~sp_counted_impl()
{
#ifdef DISPLAY
std::cout << "Free SP_COUNTED_IMPL" << std::endl;
#endif
}
private:
X* px_;
};
sysutil.h
#pragma once
#include<iostream>
#include<vld.h>
//using namespace std;
//#define DISPLAY
test.cpp
#include"shared_ptr.h"
void test01()
{
int* ptr = new int(5);
shared_ptr<int> ps(ptr);
std::cout << "ptr.use_count="<<ps.use_count() << std::endl;
shared_ptr<int>ps2(ps);
std::cout << "ptr.use_count=" << ps2.use_count() << std::endl;
/*{
shared_ptr<int>ps3(ps2);
std::cout << "ptr.use_count=" << ps3.use_count() << std::endl;
}
std::cout << "ptr.use_count=" << ps2.use_count() << std::endl;
std::cout << *ps << std::endl;*/
//int* q = new int(50);
//shared_ptr<int> ps4(q);
//std::cout << "q.use_count=" << ps4.use_count() << std::endl;
{
int* ptr2 = new int(50);
shared_ptr<int> ps5(ptr2);
ps5 = ps;
std::cout << "ptr2.use_count=" << ps5.use_count() << std::endl;
}
std::cout << "ptr2.use_count=" << ps2.use_count() << std::endl;
}
void main()
{
test01();
system("pause");
}
weak_ptr:不影响引用计数,也不能解引用
#include<iostream>
#include<vld.h>
using namespace std;
void test01()
{
int* ptr = new int(10);
shared_ptr<int> ps(ptr);
cout << "ptr.use_count=" << ps.use_count() << endl;
weak_ptr<int> pw = ps;
cout << "ptr.use_count=" << pw.use_count() << endl;//不影响引用计数
//cout << *pw << endl;//不能解引用
}
void main()
{
test01();
system("pause");
}
智能指针:异常安全但不是线程安全的,需要加锁实现互斥
1.
智能指针对象中引用计数是多个智能指针对象共享的,两个线程中智能指针的引用计数同时
++
或
--
,这个操作不是原子的,引用计数原来是
1
,
++
了两次,可能还是
2.
这样引用计数就错乱了。会导致资源未
释放或者程序崩溃的问题。所以只能指针中引用计数
++
、
--
是需要加锁的,也就是说引用计数的操作是
线程安全的。
2.
智能指针管理的对象存放在堆上,两个线程中同时去访问,会导致线程安全问题。
#include<iostream>
#include<mutex>
#include<thread>
//智能指针 异常安全但不线程安全
using namespace std;
template <class T>
class SharedPtr
{
public:
SharedPtr(T* ptr = nullptr)
: _ptr(ptr)
, _pRefCount(new int(1))
, _pMutex(new mutex)
{}
~SharedPtr()
{
Release();
}
SharedPtr(const SharedPtr<T>& sp)
: _ptr(sp._ptr)
, _pRefCount(sp._pRefCount)
, _pMutex(sp._pMutex)
{
AddRefCount();
}
SharedPtr<T>& operator=(const SharedPtr<T>& sp)
{
if (_ptr != sp._ptr)
{
Release();
_ptr = sp._ptr;
_pRefCount = sp._pRefCount;
_pMutex = sp._pMutex;
AddRefCount();
}
return *this;
}
T& operator*() { return *_ptr; }
T* operator->() { return _ptr; }
int UseCount() { return *_pRefCount; }
T* Get() { return _ptr; }
void AddRefCount()
{
_pMutex->lock();
++(*_pRefCount);
_pMutex->unlock();
}
private:
void Release()
{
bool deleteflag = false;
_pMutex->lock();
if (--(*_pRefCount) == 0)
{
delete _ptr;
delete _pRefCount;
deleteflag = true;
}
_pMutex->unlock();
if (deleteflag)
delete _pMutex;
}
private:
int* _pRefCount; // 引用计数
T* _ptr; // 指向管理资源的指针
mutex* _pMutex;
};
class Date
{
public:
Date() { cout << "Date()" << endl; }
~Date() { cout << "~Date()" << endl; }
size_t _year = 0;
size_t _month = 0;
size_t _day = 0;
};
mutex mt;
void SharePtrFunc(SharedPtr<Date>& sp, size_t n)
{
cout << sp.Get() << endl;
for (size_t i = 0; i < n; ++i)
{
SharedPtr<Date> copy(sp);
mt.lock();
copy->_year++;
copy->_month++;
copy->_day++;
mt.unlock();
}
}
int main()
{
SharedPtr<Date> p(new Date);
cout << p.Get() << endl;
const size_t n = 10000000;
thread t1(SharePtrFunc, ref(p), n);
thread t2(SharePtrFunc, ref(p), n);
t1.join();
t2.join();
cout << p->_year << endl;
cout << p->_month << endl;
cout << p->_day << endl;
return 0;
}
循环引用:
#include<iostream>
using namespace std;
struct ListNode
{
int _data;
/*shared_ptr<ListNode> _prev;
shared_ptr<ListNode> _next;*/
weak_ptr<ListNode> _prev;//解决循环引用
weak_ptr<ListNode> _next;
~ListNode() { cout << "~ListNode()" << endl; }
};
int main()
{
shared_ptr<ListNode> node1(new ListNode);
shared_ptr<ListNode> node2(new ListNode);
cout << node1.use_count() << endl;
cout << node2.use_count() << endl;
node1->_next = node2;
node2->_prev = node1;
cout << node1.use_count() << endl;
cout << node2.use_count() << endl;
return 0;
}
1. node1
和
node2
两个智能指针对象指向两个节点,引用计数变成
1
,我们不需要手动
delete
。
2. node1
的
_next
指向
node2
,
node2
的
_prev
指向
node1
,引用计数变成
2
。
3. node1
和
node2
析构,引用计数减到
1
,但是
_next
还指向下一个节点。但是
_prev
还指向上一个节点。
4.
也就是说
_next
析构了,
node2
就释放了。
5.
也就是说
_prev
析构了,
node1
就释放了。
6.
但是
_next
属于
node
的成员,
node1
释放了,
_next
才会析构,而
node1
由
_prev
管理,
_prev
属于
node2
成员,所以这就叫循环引用,谁也不会释放。
删除器的使用--属于回调函数
#include<iostream>
#include<vld.h>
using namespace std;
void ptr_delete(void* ptr)
{
cout << "Free" << endl;
free(ptr);//delete [] close
}
void test01()
{
//socket
int* ptr = (int*)malloc(sizeof(int));//malloc new[]
shared_ptr<int> ps(ptr, ptr_delete);
}
void main()
{
test01();
system("pause");
}
shared_ptr实现的简单版
// 模拟实现一份简单的SharedPtr,了解原理
#include<iostream>
#include <thread>
#include <mutex>
using namespace std;
template <class T>
class SharedPtr
{
public:
SharedPtr(T* ptr = nullptr)
: _ptr(ptr)
, _pRefCount(new int(1))
, _pMutex(new mutex)
{}
~SharedPtr() { Release(); }
SharedPtr(const SharedPtr<T>& sp)
: _ptr(sp._ptr)
, _pRefCount(sp._pRefCount)
, _pMutex(sp._pMutex)
{
AddRefCount();
}
// sp1 = sp2
SharedPtr<T>& operator=(const SharedPtr<T>& sp)
{
//if (this != &sp)
if (_ptr != sp._ptr)
{
// 释放管理的旧资源
Release();
// 共享管理新对象的资源,并增加引用计数
_ptr = sp._ptr;
_pRefCount = sp._pRefCount;
_pMutex = sp._pMutex;
AddRefCount();
}
return *this;
}
T& operator*() { return *_ptr; }
T* operator->() { return _ptr; }
int UseCount() { return *_pRefCount; }
T* Get() { return _ptr; }
void AddRefCount()
{
// 加锁或者使用加1的原子操作
_pMutex->lock();
++(*_pRefCount);
_pMutex->unlock();
}
private:
void Release()
{
bool deleteflag = false;
// 引用计数减1,如果减到0,则释放资源
_pMutex.lock();
if (--(*_pRefCount) == 0)
{
delete _ptr;
delete _pRefCount;
deleteflag = true;
}
_pMutex.unlock();
if (deleteflag == true)
delete _pMutex;
}
private:
int* _pRefCount; // 引用计数
T* _ptr; // 指向管理资源的指针
mutex* _pMutex; // 互斥锁
};
int main()
{
SharedPtr<int> sp1(new int(10));
SharedPtr<int> sp2(sp1);
*sp2 = 20;
cout << sp1.UseCount() << endl;
cout << sp2.UseCount() << endl;
SharedPtr<int> sp3(new int(10));
sp2 = sp3;
cout << sp1.UseCount() << endl;
cout << sp2.UseCount() << endl;
cout << sp3.UseCount() << endl;
sp1 = sp3;
cout << sp1.UseCount() << endl;
cout << sp2.UseCount() << endl;
cout << sp3.UseCount() << endl;
return 0;
}