您的位置:首页 > 其它

Boost源码学习二[内存管理一]中

2015-10-23 13:27 375 查看
接着一篇继续学习智能指针。。。。。。。。

第四个学习的是shared_array指针:

类摘要:

template<class T> class shared_array{

public:
     explicit shared_array(T *p = 0);
	 template<class D> shared_array(T *p,D d);
	 ~shared_array();
	 
	 shared_array(shared_array const & r);
	 shared_array &operator=(shared_array const &r);
	 
	 void reset(T *p = 0);
	 template<class D> void reset(T *p, D d);
	 
	 T & operator[](std::ptrdiff_t i) const() const;
	 T *get() const;
	 
	 bool unique() const;
	 long use_count() const;
	 
	 void swap(shared_array<T> & b);
};


shared_array与shared_ptr的区别如下:

1:构造函数接受的指针p必须是new[]的结果,而不能是new表达式。

2:提供operator[]操作符重载,可以像普通数组一样用下标访问元素。

3:没有*、->操作符重载,因为shared_array持有的不是一个普通指针。

4:析构函数使用delete[]释放资源,而不是delete。

Boost程序库开发指南的一段例子:

#include <boost/smart_ptr.hpp>
using namespace boost;
using namespace std;
int main()
{
    int *p = new int[100];

    shared_array<int> sa(p);
    assert(sa.unique());

    shared_array<int> sa2 = sa;
    assert(sa2.use_count() == 2);

    sa[0] = 10;
    assert(sa2[0] == 10);
}<span style="font-family:Microsoft YaHei;font-size:18px;">
</span>

第五个学习的是weak_ptr指针:

weak_ptr是为配合shared_ptr而引入的一种智能指针,它更像是shared_ptr的一个助手,而不是智能指针,因为它不具有普通指针的行为,没有重载operator*和operator->,它的最大作用在于协助shared_ptr,像旁观者那样观测资源的使用情况。

template<class T> class weak_ptr{
     public:
	 weak_ptr();
	 template<class Y> weak_ptr(shared_ptr<Y> const & r);
	 weak_ptr(weak_ptr const & r);
	 
	 ~weak_ptr();
	 weak_ptr & operator=(weak_ptr const &r);
	 
	 long use_count() const;
	 bool expired() const;
	 shared_ptr<T> lock() const;
	 
	 void reset();
	 void swap(weak_ptr<T> &b);	
};
特点:

weak_ptr被设计为与shared_ptr共同工作,可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。同样,在weak_ptr析构时也不会导致引用计数的减少,它只是一个静静地观察者。

使用weak_ptr的成员函数use_count()可以观测资源的引用计数,另一个成员函数expired()的功能等价于use_count() == 0,但更快,表示观测的资源(也就是shared_ptr管理的资源)已经不复存在了。

weak_ptr 没有重载operator*和->,这是特意的,因为它不共享指针,不能操作资源,这是它弱的原因。但它可以使用一个非常重要的成员函数lock()从被观测的shared_ptr获得一个可用的shared_ptr对象,从而操作资源。当expired() == true的时候,lock()函数将返回一个存储空指针的shared_ptr。(摘自Boost程序库完全开发指南)

weak_ptr的一个重要用途是获得this指针的shared_ptr,使对象自己能够生产shared_ptr管理自己:对象使用weak_ptr观测this指,这并不影响引用计数,在需要的时候就调用lock()函数,返回一个符合要求的shared_ptr使外界使用。

这个解决方案被实现为一个惯用法,在头文件<booost/enable_shared_from_this.hpp>定义了一个助手类enable_shared_from_this<T>,其声明如下:

template<class T>
class enable_shared_from_this
{
public:
   shared_ptr<T> shared_from_this();
}

使用的时候只需要让想被shared_ptr管理的类从它继承即可,成员函数shared_from_this()会返回this的shared_ptr。

#include <iostream>
#include <boost/smart_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/make_shared.hpp>
using namespace boost;
using namespace std;
class self_shared:
public enable_shared_from_this<self_shared>{
	public:
    self_shared(int n):x(n){}
    int x;
    void print(){
    cout << "self_shared:" << x << endl;
    }
};
int main(){
    shared_ptr<self_shared> sp = 
	                       make_shared<self_shared>(315);
	sp->print();
	shared_ptr<self_shared> p = sp->shared_from_this();
	p->x = 100;
	p->print();	

}


需要注意的是千万不能从一个普通对象(非shared_ptr)使用shared_from_this ()获取shared_ptr,如

self_shared ss;

shaerd_ptr<self_shared> p = ss.shared_from_this();//error

这样虽然语法上能通过,编译也无问题,但在运行时会导致shared_ptr析构时企图删除一个栈上分配的对象,发生未定义行为。

类似的辅助类enable_shared_from_raw,它不要求对象必须被一个shared_ptr管理,可以直接从一个原始指针创建出shared_ptr。

class enable_shared_from_raw
{
protected:
	enable_shared_from_raw();
	enable_shared_from_raw(enable_shared_from_raw const &);
	enable_shared_from_raw & operator=(enable_shared_from_raw const &);
	~enable_shared_from_raw();
private:
	template<class Y> friend class shared_ptr;
	template<typename T> friend boost::shared_ptr<T> shared_from_raw(T *);
	template<typename T> friend boost::weak_ptr<T> weak_from_raw(T *);
};

Boost程序员完全开发指南的例子:

#include <boost/smart_ptr.hpp>
using namespace boost;
//////////////////////////////////////////
void case1()
{
    shared_ptr<int> sp(new int(10));
    assert(sp.use_count() == 1);

    weak_ptr<int> wp(sp);
    assert(wp.use_count() == 1);

    if (!wp.expired())
    {
        shared_ptr<int> sp2 = wp.lock();
        *sp2 = 100;
        assert(wp.use_count() == 2);
    }

    assert(wp.use_count() == 1);
    sp.reset();
    assert(wp.expired());
    assert(!wp.lock());
}

//////////////////////////////////////////

class self_shared:
    public enable_shared_from_this<self_shared>
{
public:
    self_shared(int n):x(n){}
    int x;
    void print()
    {   std::cout << "self_shared:" << x << std::endl;    }
};

void case2()
{
    auto sp = make_shared<self_shared>(313);
    sp->print();

    auto p = sp->shared_from_this();

    p->x = 1000;
    p->print();
}

//////////////////////////////////////////

class node
{
public:
    ~node()
    {     std::cout << "deleted" << std::endl;}

    typedef weak_ptr<node> ptr_type;
    //typedef shared_ptr<node> ptr_type;
    ptr_type next;
};
//打破循环引用
void case3()
{
    auto p1 = make_shared<node>();
    auto p2 = make_shared<node>();

    p1->next = p2;
    p2->next = p1;

    assert(p1.use_count() == 1);
    assert(p2.use_count() == 1);

    if(!p1->next.expired())
    {
        auto p3 = p1->next.lock();
    }
}

//////////////////////////////////////////
#include <boost/smart_ptr/enable_shared_from_raw.hpp>

class raw_shared:
    public enable_shared_from_raw
{
public:
    raw_shared()
    {   std::cout << "raw_shared ctor" << std::endl;    }
    ~raw_shared()
    {   std::cout << "raw_shared dtor" << std::endl;    }
};

void case4()
{
    raw_shared x;
    assert(!weak_from_raw(&x).use_count());
    auto px = shared_from_raw(&x);
    assert(px.use_count() == 2);

    auto p = new raw_shared;

    auto wp = weak_from_raw(p);
    assert(wp.use_count() == 0);

    decltype(shared_from_raw(p)) spx(p);

    auto sp = shared_from_raw(p);
    //std::cout << sp.use_count() << std::endl;
    assert(sp.use_count() == 2);

    //decltype(sp) spx(p);

    auto sp2 = sp;
    auto wp2 = weak_from_raw(p);
    assert(wp2.use_count() == 3);
}

//////////////////////////////////////////

int main()
{
    case1();
    case2();
    case3();
    case4();
}

最后学习一下第六个指针intrusive_ptr:

template<class T> class intrusive_ptr {
public:
	//被代理的对象
	typedef T element_type;
	//构造函数
	intrusive_ptr();
	/*这个构造函数将指针p保存到*this中。如果 p 非空,并且 add_ref 为 true, 
	构造函数将调用 intrusive_ptr_add_ref(p). 如果 add_ref 为 false, 
	构造函数则不调用 intrusive_ptr_add_ref. 如果intrusive_ptr_add_ref会抛出异常,
	则构造函数也会。*/
	intrusive_ptr(T* p, bool add_ref = true);
	/*该复制构造函数保存一份r.get()的拷贝,并且如果指空非空则用
	它调用 intrusive_ptr_add_ref 。这个构造函数不会抛出异常。*/
	intrusive_ptr(const intrusive_ptr& r);
	~intrusive_ptr();
	/*解引用操作符返回所存指针的解引用。如果所存指针为空则会导致未定义行为。
	你应该确认intrusive_ptr有一个非空的指针,这可以用函数 get 实现,
	或者在Boolean上下文中测试 intrusive_ptr 。解引用操作符不会抛出异常。
	要使用引用,取得一个对象的地址,传给别的函数,当然需要再解引用,
	取得对象的具体状态,或进行相应的操作。*/
	T & operator*() const;
	T * operator->() const;
	T * get() const;
	/*这个类型转换函数返回一个可用于布尔表达式的类型,而它绝对
	不是 operator bool, 因为那样会允许一些必须要禁止的操作。
	这个转换允许intrusive_ptr在一个布尔上下文中被测试,
	例如,if (p), p 是一个 intrusive_ptr. 这个转换函数当intrusive_ptr引向一个
	非空指针时返回True ; 否则返回 false. 这个转换函数不会抛出异常。*/
	operator unspecified - bool - type() const;
};
/*这个函数返回 p.get(), 它主要用于支持泛型编程。
它也可以用作替代成员函数 get, 因为它可以重载为可以与裸指针或
第三方智能指针类一起工作。有些人宁愿用普通函数而不用成员函数。
这种想法是出于以下原因,使用智能指针的成员函数时,很难分清它
是操作智能指针还是操作它所指向的对象。
例如, p.get() 和 p->get() 有完全不同的意思,不认真看还很难区别,
而 get_pointer(p) 和 p->get() 则一看就知道不一样。对于你来说这是不是问题,
主要取决于你的感觉和经验。
*/
template <class T> T* get_pointer(const intrusive_ptr<T>& p);
/*这个函数返回 intrusive_ptr<T>(static_cast<T*>(r.get())). 和 shared_ptr不一样,
你可以对保存在intrusive_ptr中的对象指针安全地使用static_cast。
但是你可能出于对智能指针类型转换的用法一致性而想使用这个函数*/
template <class T, class U> intrusive_ptr<T>
	static_pointer_cast(const intrusive_ptr<U>& r);

该指针主要的一个功能是提供一个引用计数器,引用计数是一个初始化为零的私有数据成员,我们将公开 add_ref 和 release 成员函数来操作它。add_ref 递增引用计数而 release 递减它。 我们可以增加一个返回引用计数当前值的成员函数,但release也可以做到这一点。下面的基类,reference_counter, 提供了一个计数器以及
add_ref 和 release 成员函数,我们可以简单地用继承来为一个类增加引用计数了。

class reference_counter {
  int ref_count_;
  public:
    reference_counter() : ref_count_(0) {}
  
    virtual ~reference_counter() {}

    void add_ref() { 
      ++ref_count_;
    }

    int release() {
      return --ref_count_;
    }

  protected:
    reference_counter& operator=(const reference_counter&) {
    // 无操作
      return *this;
    }
  private:
    // 禁止复制构造函数
    reference_counter(const reference_counter&); 
};

把reference_counter的析构函数声明为虚拟的原因是这个类将被公开继承,有可能会使用一个reference_counter指针来delete派生类。我们希望删除操作能够正确地调用派生类的析构函数。实现非常简单:add_ref 递增引用计数,release 递减引用计数并返回它。要使用这个引用计数,要做的就是公共地继承它。

使用例子:

#include <boost/smart_ptr.hpp>
using namespace boost;
using namespace std;
//////////////////////////////////////////
struct counted_data
{
    // ...
    int m_count = 0;
    ~counted_data()
    {
        cout << "dtor" << endl;
    }
};

void intrusive_ptr_add_ref(counted_data* p)
{
    ++p->m_count;
}

void intrusive_ptr_release(counted_data* p)
{
    if(--p->m_count == 0)
    {
        delete p;
    }
}
//////////////////////////////////////////
#include <boost/smart_ptr/intrusive_ref_counter.hpp>

struct counted_data2 : public intrusive_ref_counter<counted_data2>
{
    ~counted_data2()
    {
        cout << "dtor2" << endl;
    }
};
//////////////////////////////////////////

int main()
{
    typedef intrusive_ptr<counted_data> counted_ptr;

    counted_ptr p(new counted_data);
    assert(p);
    assert(p->m_count == 1);

    counted_ptr p2(p);
    assert(p->m_count == 2);

    counted_ptr weak_p(p.get(), false);
    assert(weak_p->m_count == 2);

    p2.reset();
    assert(!p2);
    assert(p->m_count == 1);

    {
        typedef intrusive_ptr<counted_data2> counted_ptr;

        counted_ptr p(new counted_data2);
        assert(p);
        assert(p->use_count() == 1);

    }
}

最后插一个相对比较有用的make_shared的结尾曲:

一个自由工厂函数make_shared<T>(),来消除显式的new调用,它的名字模仿了标准库的make_pair(),声明如下:template<class T,class...Args>shared_ptr<T> make_shared(Args &&& ... args);

make_shared()函数可以接受最多10个参数,然后把它们传递给类型T的构造函数,创建一个shared_ptr<T>的对象并返回。make_shared()函数比直接创建shared_ptr对象的方式快且高效,因为它内部仅分配了一次内存,消除了shared_ptr构造时的开销。

使用:

#include <iostream>
#include <boost/smart_ptr.hpp>
#include <boost/make_shared.hpp>
#include <vector>
using  namespace std;
using namespace boost;
int main(){
	//create a shared pointer for string
    shared_ptr<string> sp = 
                       make_shared<string>("make shared");
    cout << *sp << endl;
    //create a shared pointer for vector<int>
    shared_ptr<vector<int> > spv = 
                       make_shared<vector<int> > (10,2);
    assert(spv->size() == 10);
    cout << "No problem." << endl;
}
ptr指针的例子小回顾:

// scoped_ptr.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <boost/scoped_ptr.hpp>
#include <string>
#include <iostream>
#include <vector>
using namespace std;
using namespace boost;

void scoped_vs_auto();

int _tmain(int argc, _TCHAR* argv[])
{
	// 正常用法
	scoped_ptr<string> p(new string("User scoped_ptr often."));
	if (p)
	{
		cout << *p << '\n';
		cout << "sizeof(\"" << *p << "\") = " << p->size() << endl;
		*p = "Acts just like a pointer";
		cout << "After Change:" << endl;
		cout << "sizeof(\"" << *p << "\") = " << p->size() << endl;
	}

	// 自增自减操作——不支持
	//p++;
	//p--;

	// scoped_ptr和auto_ptr的比较
	// scoped_ptr不能被赋值或复制构造
	scoped_vs_auto();
	
	// 因为不支持赋值和复制构造,所以不能作为容器的元素
	//vector<scoped_ptr<string>> vecp;
	//vecp.push_back(p);

	// scoped_ptr
	getchar();
	return 0;
}

void scoped_vs_auto()
{
	scoped_ptr<string> p_scoped(new string("hello"));
	auto_ptr<string> p_auto(new string("hello"));
	p_scoped->size();
	p_auto->size();
	// 编译不通过,不能被赋值
	//scoped_ptr<string> p_another_scoped = p_scoped;
	auto_ptr<string> p_another_auto = p_auto;
	p_another_auto->size();
	(*p_auto).size();
}
======================================================

/*它可以指向相同的内容,靠引用计数来决定内容是否释放。其中new int申请的空间,
在三个指向它的指针全部释放时才被释放,否则只是引用计数减一。*/
#include <cassert>
#include <boost/shared_ptr.hpp>

int _tmain(int argc, _TCHAR* argv[])
{
	boost::shared_ptr<int> tmp(new int(50));
	boost::shared_ptr<int> a = tmp;
	boost::shared_ptr<int> b = tmp;

	*a = 100;

	assert(*b == 100);

	getchar();
	return 0;
}
/*能作为容器元素来使用。*/
#include <iostream>
#include <vector>
#include <boost/shared_ptr.hpp>

class counter
{
public:
	static int _no;
	counter()
	{
		_no++;
	}
	~counter()
	{
		_no--;
	}
	static void Speak()
	{
		std::cout << "Total " << _no << " Objects!" << std::endl;
	}
};
int counter::_no = 0;

int _tmain(int argc, _TCHAR* argv[])
{
	typedef boost::shared_ptr<counter> element;
	typedef std::vector<element> container;
	typedef std::vector<element>::iterator iterator;
	element a(new counter());
	element b(new counter());
	element c(new counter());
	element d(new counter());
	element e(new counter());
	container cr;
	cr.push_back(a);
	cr.push_back(b);
	cr.push_back(c);
	cr.push_back(d);
	cr.push_back(e);

	for (iterator it = cr.begin(); it != cr.end(); ++it)
	{
		(*it)->Speak();
	}

	cr.clear();

	getchar();
	return 0;
}
/*shared_ptr可以定制删除器,来处理非delete和delete[]能够处理的资源,如示例中的文件描述符等。
shared_ptr指向指针时,原来的指针调用方式为:&*sp,*sp表示是对象,&(*sp)代表是指针。可以用sp.get()来替代。
*/
#include "boost/shared_ptr.hpp"
#include <vector>
#include <cassert>
#include <iostream>
#include <cstdio>

class FileCloser
{
public:
	void operator()(FILE* file)
	{
		std::cout << "The FileCloser has been called with a FILE*, which will now be closed.\n";
		if (file != 0)
		{
			std::fclose(file);
		}
	}
};

int _tmain(int argc, _TCHAR* argv[])
{
	{	// 在此作用域内文件打开会自动关闭
		FILE *f = std::fopen("test.txt", "r");
		if (f == 0)
		{
			std::cout << "Unable to open file\n";
			throw "Unable to open file";
		}
		boost::shared_ptr<FILE> sf(f, FileCloser());
		std::fseek(sf.get(), 100, SEEK_SET);
		std::fseek(&*sf, 100, SEEK_SET);
	}

	std::cout << std::endl;
}
/*第二个例子演示了安全删除器的方法,并且演示了删除函数的规则:实现operator()(TYPE *p){}函数。*/
#include "boost/shared_ptr.hpp"
#include <iostream>
class A
{
	// 嵌套类
	class deleter
	{
	public:
		// 重载运算符()
		void operator()(A* p)
		{
			delete p;
		}
	};
	// 声明为友元类,再进行嵌套实现,实现了安全访问。
	friend class deleter;
public:
	virtual void sing()
	{
		std::cout << "Lalalalalalalalalalala";
	}
	// 构造器
	static boost::shared_ptr<A> createA()
	{
		boost::shared_ptr<A> p(new A(), A::deleter());
		return p;
	}
protected:
	virtual ~A() {};
};

int main()
{
	// 构造函数创建出来一个类,然后直接调用,不用管理释放的任何操作。
	boost::shared_ptr<A> p = A::createA();
}
未完。。。。。。。。



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: