题目
原文:
Write a smart pointer (smart_ptr) class.
译文:
写一个智能指针类(smart_ptr)。
分析
比起一般指针,智能指针会自动地管理内存(释放不需要的内存),而不需要程序员去操心。 它能避免迷途指针(dangling pointers),内存泄漏(memory leaks), 分配失败等情况的发生。
C++自带的智能指针主要有四种:
1.auto_ptr和2.scoped_ptr主要是针对指针管理权限加以约束使得两个指针不能同时管理一块内存空间;
而我们今天主要模拟的是3.shared_ptr共享指针,这意味多个智能指针可以共同指向一块空间,只不过需要增加一个引用计数指针加以管理。
话不多说,直接看代码即可:
代码
#include<iostream>
using namespace std;
template <typename T>
class SmartPointer {
public:
SmartPointer(T* p) {
sp = p;
count = new unsigned(1);
}
SmartPointer(SmartPointer<T> &sptr) {
sp = sptr.sp;
count = sptr.count;
//两指针指向的内存计数均加一
++(*count);
}
SmartPointer<T>& operator=(SmartPointer<T> &sptr) {
if(this != &sptr) {
//没有更多的指针指向这块内存时才清空指向的内存
if(--(*count) == 0) {
cout << "SmartPointer " << *sp;
clear();
cout << " operator = cleear" << endl;
}
sp = sptr.sp;
count = sptr.count;
++(*count);
}
return *this;
}
~SmartPointer() {
cout << "delete a pointer point to " << *sp << endl;
//没有更多的指针指向这块内存时才清空指向的内存
if(--(*count) == 0) {
cout << "~SmartPointer " << *sp;
clear();
cout << " cleear" << endl;
}
}
T* operator->() {
return sp;
}
T& operator*() {
return *sp;
}
unsigned GetCount() {
return *count;
}
private:
//当没有更多的引用计数时,delet指针指向的内存
void clear() {
delete sp;
delete count;
sp = NULL;//避免成为迷途指针
count = NULL;
}
protected:
T* sp;
unsigned* count;
};
int main() {
int *p1 = new int(11);
int *p2 = new int(22);
SmartPointer<int> p3(p1);
cout << "p3 is " << *p3 << ", and count is " << p3.GetCount() << endl;
SmartPointer<int> p4(p2);
cout << "p4 is " << *p4 << ", and count is " << p4.GetCount() << endl;
SmartPointer<int> p5(p3);
*p5 = 33;
cout << "p5 is " << *p5 << ", and count is " << p5.GetCount() << endl;
cout << "p3 is " << *p3 << ", and count is " << p3.GetCount() << endl;
p3 = p4;
cout << "p3 is change, but now operator = cleear not happend." << endl;
cout << "p5 is " << *p5 << ", and count is " << p5.GetCount() << endl;
p5 = p4;
cout << "p5 is " << *p5 << ", and count is " << p5.GetCount() << endl;
return 0;
}
结果
问题及改进
但是shared_ptr会出现一个问题,就是循环引用,就会导致引用计数一直无法减到0,就会导致空间没有释放,比如双向链表中如果使用上述智能指针,a1->next=a2和a2->pre=a1,这时a1的释放又依赖于a2->pre,a2的pre的释放又依赖于a2,a2又依赖于a1的next的释放,a1里的next和pre两个指针的释放依赖于a1,这将导致循环依赖无法释放,最终导致内训泄露。
这时我们采用weak_ptr解决循环引用的问题,将会出现循环引用的shared_ptr通过weak_ptr的构造函数保存下来。
这是因为并且weak_ptr里面不增加引用计数。但是它不是严格意义上的智能指针,它只是辅助shared_ptr的使用,为了解决shared_ptr循环引用问题引入的。