智能指针

来源:互联网 发布:微信加粉软件 编辑:程序博客网 时间:2024/05/10 07:12

我们都知道指针是指向一片内存空间的,可是当两个指针指向同一空间,假如要销毁一个指针,那这一片空间应该也被销毁,那么此时另一个指针应该怎样?

针对这样的问题,人们想出了“智能指针”。

auto_ptr:

template <class T>class Auto_ptr {private:T *ptr;public:Auto_ptr(T *p):ptr(p){}~Auto_ptr(){delete ptr;}};int main(){Auto_ptr<int> p(new int(1));Auto_ptr<int> p1(new int);p = p1;return 0;}
此时析构时,两个对象都是用了一个指针,也就是说,两个对象同用了一片内存空间,这样在析构时,同一片内存将会被释放两次,程序就会出错。
将auto_ptr改进一下,使只有一个指针指向一片空间是才能够释放
#include<iostream>using namespace std;template <class T>class Auto_ptr {private:T *_ptr;bool _owner;public:Auto_ptr(T *p):_ptr(p),_owner(true){}~Auto_ptr(){if (_owner) { delete _ptr; }}Auto_ptr& operator=(Auto_ptr &p){if (this != &p){if (_owner){delete _ptr;}_ptr = p._ptr;_owner = p._owner;p._owner = false;}return *this;}Auto_ptr(Auto_ptr &p){_ptr = p._ptr;_owner = p._owner;p._owner = false;}};int main(){Auto_ptr<int> p(new int(1));Auto_ptr<int> p1(new int);p = p1;return 0;}
 scoped_ptr:

这个很简单粗暴,它禁止了赋值操作和复制构造。

class scoped_ptr{public:scoped_ptr(T *p):_ptr(p){}private:scoped_ptr(scoped_ptr &p);private:T *_ptr;}
他将拷贝构造函数定义为私有,直接禁止了复制构造。

但是如果程序需要在多个不同的地方用到同一份内容,那么就会很麻烦。因此人们又想出了share_ptr
share_ptr:

class shared_ptr{private:T *_ptr;int *_count;public:shared_ptr(T *p):_ptr(p),_count(new int(1)){}~shared_ptr(){if (!(--(*_count))){delete _ptr;delete _count;_ptr = NULL;_count = NULL;
cout << "~xigou" << endl;}else{--(*_count);}}shared_ptr(shared_ptr &p):_ptr(p._ptr),_count(p._count){++(*count);}shared_ptr& operator=(shared_ptr &p){if (_ptr != p._ptr){if ((*_count) == 1){delete _ptr;delete _count;}_ptr = p._ptr;_count = p._count;++(*(_count));}return *this;}};int main(){shared_ptr<int> p(new int(1));shared_ptr<int> p1(new int);p = p1;return 0;}
shared_ptr使用引用计数!每次有一个shared_ptr关联到某个对象上时,计数值就加上1;相反,每次有一个shared_ptr析构时,相应的计数值就减去1。当计数值减为1的时候,就执行对象的析构函数,此时该对象才真正被析构!由此,shared_ptr很明显是支持复制构造和赋值操作的,因为它有了计数机制之后,就不需要scoped_ptr那样严格地控制复制、赋值来维护析构操作的时机。
struct BB{int date;shared_ptr<BB> next;shared_ptr<BB> prev;BB() :date(0), next(0), prev(0){}};int main(){shared_ptr<BB> p(new BB());shared_ptr<BB> p1(new BB());}

运行结果为:


而人们又渐渐的发现了循环引用,如下:

int main(){shared_ptr<BB> p(new BB());shared_ptr<BB> p1(new BB);p->s = p1;p1->f = p;}
此时只析构两次。为什么呢?
除了p的prev和p1的next,其他都没被释放,

一般来讲,解除这种循环引用有下面方法:

  1. 当只剩下最后一个引用的时候需要手动打破循环引用释放对象
  2. 使用弱引用的智能指针打破这种循环引用。

但方法1需要程序员手动控制,麻烦且容易出错。这里主要介绍一下第三种方法,弱引用的智能指针weak_ptr。

weak_ptr:

template <class T>class weak_ptr {private:T *_ptr;public:weak_ptr(T *p):_ptr(p){}~weak_ptr(){cout << "    " << endl;delete _ptr;}weak_ptr& operator=(shared_ptr p){_ptr = p._ptr;};};
由于弱引用不更改引用计数,类似普通指针,只要把循环引用的一方使用弱引用,即可解除循环引用。

最后值得一提的是,虽然通过弱引用指针可以有效的解除循环引用,但这种方式必须在程序员能预见会出现循环引用的情况下才能使用,也可以是说这个仅仅是一种编译期的解决方案,如果程序在运行过程中出现了循环引用,还是会造成内存泄漏的。因此,不要认为只要使用了智能指针便能杜绝内存泄漏。


仿函数:

#include<iostream>using namespace std;struct cm {bool operator()(int a, int b){return (a > b);}};int main(){cm a;a(1, 2);    return 0;}

删除器:

#include<iostream>using namespace std;//文件删除器struct Fclose{void operator()(FILE*& fp){cout << "Fclose()" << endl;fclose(fp);}};//普通删除器struct del{void operator()(void *p){delete(p);p = NULL;}};




原创粉丝点击