智能指针——shared_ptr&weak_ptr
程序员文章站
2022-06-02 13:56:27
...
一个带有定制删除器的shared_ptr,因为有些指针比如说文件中指针,我们在释放文件指针的时候不能简单的使用free直接将文件指针释放掉,此时我们就应该传入一个仿函数,在我们传入文件指针的时候,调用这个仿函数来释放这个指针即可,不同的指针定制不同的释放函数这是我们的思想
template <class T>
struct Delete
{
void operator()(T *_ptr)
{
if (_ptr)
{
delete _ptr;
}
}
};
//文件仿函数
struct Fclose
{
void operator()(FILE *ptr)
{
fclose(ptr);
}
};
//定制一个删除的仿函数
template <class T,class D = Delete<T>>
class Shared_ptr
{
public:
//没有定制删除器的Shared_ptr
Shared_ptr(T *ptr)
:_ptr(ptr),
_pcount(new int(1))
{}
//有定制删除器的
Shared_ptr(T *ptr, D d)
:_ptr(ptr),
_pcount(new int(1)),
_d(d)
{}
//拷贝构造
//不拷贝直接++
Shared_ptr(const Shared_ptr<T, D>& ap)
:_ptr(ap._ptr),
_pcount(ap._pcount)
{
++(*ap._pcount);
}
//赋值运算符的重载
Shared_ptr<T, D>& operator=(Shared_ptr<T, D>& ap)
{
if (this != &ap)
{
//当引用计数为1的时候直接删除,然后赋值
if (--(*_pcount) == 0)
{
delete _ptr;
delete _pcount;
}
}
//当引用计数不为1的时候,直接赋值即可
_ptr = ap._ptr;
_pcount = ap._pcount;
++(*_pcount);
return *this;
}
~Shared_ptr()
{
if (--(*_pcount) == 0)
{
delete _pcount;
if (_ptr)
{
_d(_ptr);
printf("delete %p", _ptr);
}
}
}
T *operator->()
{
return _ptr;
}
T &operator*()
{
return *_ptr;
}
operator void*()
{
return _ptr;
}
public:
T *_ptr;
int *_pcount;
D _d;//定制删除器
};
void test()
{
Shared_ptr<string> sp(new (string));
Shared_ptr<FILE, Fclose> sp3(fopen("test.txt", "w"), Fclose());
}
int main()
{
test();
}
但是此时我们的shared_ptr还有一个循环引用的问题
栗子
struct ListNode
{
Shared_ptr<ListNode> _prev;
Shared_ptr<ListNode> _next;
int _data;
ListNode()
:_prev(NULL),
_next(NULL)
{}
};
void ListTest()
{
Shared_ptr<ListNode> node1 = new ListNode;
Shared_ptr<ListNode> node2 = new ListNode;
node1->_next = node2;
node2->_prev = node1;
}
解决方法:weak_ptr
template <class T>
class Weak_ptr
{
public:
Weak_ptr(const Shared_ptr<T>& ap)
:_ptr(ap._ptr)
{}
T* operator->()
{
return _ptr;
}
T& operator*()
{
return *_ptr;
}
T *_ptr;
};
struct ListNode
{
//有循环引用的
/*Shared_ptr<ListNode> _prev;
Shared_ptr<ListNode> _next;*/
//无循环引用
Weak_ptr<ListNode> _prev;
Weak_ptr<ListNode> _next;
int _data;
ListNode()
:_prev(NULL),
_next(NULL)
{}
};
void ListTest()
{
Shared_ptr<ListNode> node1 = new ListNode;
Shared_ptr<ListNode> node2 = new ListNode;
cout << *(node1._pcount) << endl;
cout << *(node2._pcount) << endl;
node1->_next = node2;
node2->_prev = node1;
cout << *(node1._pcount) << endl;
cout << *(node2._pcount) << endl;
}
有循环引用的结果
无循环引用的结果
其实我们只是将两个节点之间的指针换成了weak_ptr,没有引用计数的指针,那此时就当然不会存在循环引用的问题了,想释放直接一下就可以释放,而将我们的node1和node2设为shared_ptr,这个有循环引用是没有问题的,不会发生循环引用