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

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

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; } };