boost的內存管理


smart_ptr

  • raii ( Resource Acquisition Is Initialization )
  • 智能指針系列的都統稱為smart_ptr,包括c++98標准的auto_ptr
  • 智能指針是一個類,通過重載->和*完成類似原始指針的操作。不過因為是類,所以可以做比如內存管理、線程安全之類的工作
  • 智能指針均是自動管理內存,不需要顯示調用delete

scoped_ptr

  • 與auto_ptr最大的不同,是私有化構造和拷貝構造,使操作權不能轉讓,所以有強作用域屬性,而且指針類自己負責釋放
  • 與c++11標准的unique_ptr相比:unique_ptr有更多功能,可以像原始指針一樣進行比較、像shared_ptr一樣定制刪除器,也可以安全地放入標准容器。但是少即是多,scope_ptr專注於強調作用域屬性。

scoped_array

  • 與scoped_ptr類似,只不過封裝的是new[]分配數組。
  • 不是指針,也就沒有實現*和->的重載,而是直接[]下標訪問
  • 通常不建議使用scoped_array,它的出現通常往往意味着你的代碼中存在着隱患

shared_ptr(重點)

  • boost.smart_ptr中最有價值、最重要的組成部分,也最經常用
  • unique()在shared_ptr是指針中唯一所有者時返回true
  • user_count()返回當前指針的引用計數
  • 提供operator<、==比較操作 ,使shared_ptr可以被用於set/map標准容器
  • 編寫多態指針時,不能使用諸如static_cast< T* >(p.get())的形式,這將導致轉型后的指針無法再被shared_ptr正確管理。為了支持這樣的用法,shared_ptr提供內置的轉型函數static_pointer_cast< T >()、const_pointer_cast< T >()和dynamic_pointer_cast< T >()
  • 支持operator< < 操作打印指針值,便與調試
  • 有工廠函數
template< class T, calss... Args >
shared_ptr< T> make_shared(Args && ... args);
  • 使用代碼案例:
shared_ptr< string > sps(new string("smart"));
assert(sps->size() == 5);
shared_ptr< string> sp = make_shared< string > ("make_shared");
shared_ptr< vector< int >> spv = make_shared< vector< int >> (10,2);
assert(spv->size() == 10);
  • 應用於標准容器代碼案例:
#include < boost/make_shared.hpp>
int main()
{
typedef vector< shared_ptr< int>> vs;
vs v(10);
int i=0;
for (vs::iterator pos = v.begin(); pos != v.end(); ++pos)
{
(*pos) = make_shared< int>(++i);
cout << *(*pos) << ",";
}
cout << endl;
shared_ptr < int > p = v[9];
*p = 100;
cout << *v[9] << endl;
}

shared_array

  • 通常用shared_ptr< std::vector>或者std::vector< shared_ptr>代替

weak_ptr(重點)

  • 未重載*和->,最大的作用是協助shared_ptr,觀測資源使用情況
  • 代碼示例:
int testWeakPtr()
{
boost::shared_ptr<int> sp(new int(10));
assert(sp.use_count() == 1);

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

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

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

return 0;
}
  • 作用是打破循環引用,代碼示例:
// 循環引用的情形
class node
{
public:
boost::shared_ptr<node> next;
~node()
{
cout << "delete node" << endl;
}
};

int testWeakPtrRecycleWrong()
{
auto n1 = boost::make_shared<node>();
auto n2 = boost::make_shared<node>();

n1->next = n2;
n2->next = n1;

assert(n1.use_count() == 2);
assert(n2.use_count() == 2);

return 0; // 循環引用,析構異常,程序退出時仍未析構
}

// 避免循環引用的情形,主要就是node里的shared_ptr換成weak_ptr
class node1
{
public:
boost::weak_ptr<node1> next;
~node1()
{
cout << "delete node1" << endl;
}
};

int testWeakPtrRecycleRight()
{
auto n1 = boost::make_shared<node1>();
auto n2 = boost::make_shared<node1>();

n1->next = n2;
n2->next = n1;

assert(n1.use_count() == 1);
assert(n2.use_count() == 1);

if (!n1->next.expired())
{
// 調用lock()獲得強引用,計數加1
auto n3 = n1->next.lock();
assert(n2.use_count() == 2);
}
assert(n2.use_count() == 1);
return 0;
}

intrusive_ptr(略)

pool(pool后綴的都是重點)

  • pool管理內存,只能針對基礎類型POD(Plain Old Data),因為不調用對象的構造函數。除非特殊情況,不需要自己釋放
  • 調用示例代碼:
int testPool()
{
pool<> pl(sizeof(int));
int *p = static_cast<int*>(pl.malloc()); // void*->int*
assert(pl.is_from(p));

pl.free(p);
for (int i = 0; i < 100;i++)
{
pl.ordered_malloc(10);
}
return 0;
}

object_pool

  • pool的子類,實現對類實例(對象)的內存池,會調用析構函數正確釋放資源
  • 示例代碼:
struct demo_class
{
public:
int a, b, c;
demo_class(int x = 1, int y = 2, int z = 3) : a(x), b(y), c(z) {}
~demo_class()
{
cout << "destruct" << endl;
}
};

int testObjPool()
{
object_pool<demo_class> pl;
demo_class *p = pl.malloc();
assert(pl.is_from(p));

// malloc 創建時內存並未初始化
assert(p->a!= 1 || p->b != 2 || p->c != 3);

p = pl.construct();

// boost自帶的construct只能支持3個及以內的參數調用
p = pl.construct(7, 8, 9);
assert(p->a == 7);

object_pool<string> pls;
for (int i = 0; i < 10; i++)
{
string *ps = pls.construct("hello object_pool");
cout << *ps << endl;
}
return 0;
}

析構會調用三次,malloc和兩次construct均需要調用析構。是object_pool判斷出了作用域自動調整的。

singleton_pool

  • 基礎類型靜態單件(包括基礎指針類型),提供線程安全
  • 示例代碼
struct pool_tag{
int tag;
};
typedef singleton_pool<pool_tag, sizeof(pool_tag*)> spl;
int testSingletonPool()
{
pool_tag **p = (pool_tag **)spl::malloc();
assert(spl::is_from(p));

pool_tag ptag;
ptag.tag = 3;
*p = &ptag;

cout << "testSingletonPool : " << (*p)->tag << endl;
spl::release_memory();
return 0;
}

pool_alloc

  • 提供對標准容器類型的內存分配器,當分配失敗時可以拋異常。但是除非特別需求,應該使用stl自帶的。如果要用pool_alloc需經過仔細測試,保證與容器可以正常工作。

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com