1. RAII机制
为了管理内存等资源,C++程序员通常采用RAII机制(资源获取即初始化,Resource Acquisition Is Initialization),在使用资源的类的构造函数中申请资源,然后使用,最后在析构函数中释放资源。
1)在栈上创建对象(局部对象):RAII机制正常工作,当离开作用域时,对象会自动销毁从而调用析构函数释放资源
2)在堆上创建对象,使用new操作符,那么它的析构函数不会自动调用,只有对应的delete操作符销毁它才能释放资源。
2. 智能指针
STL中收录: #include <memory>
1)shared_ptr 允许多个指针指向同一个对象
2)unique_ptr 独占所指向的对象
3)weak_ptr 指向shared_ptr所指管理的对象,不控制对象生命周期。
2.1 shared_ptr, 工厂函数
引用计数型的智能指针,可以被自由的拷贝和赋值,在任意地方共享它,当没有代码使用(引用计数为0)时才删除被包装的动态分配的对象。
shared_ptr 很好的消除了显示的delete调用,完全可以不再使用delete。
//
shared_ptr<int> sp(new int(10)); //一个指向整数的shared_ptr
shared_ptr<int> sp2=sp; //拷贝
//较复杂的用法
void print_func(shared_ptr<int> p)
{
//do something
cout<<p.use_count()<<endl; //引用计数
}
//函数接受shared_ptr对象作为参数,特别注意的是,并没有使用引用的方式传递参数,而是直接拷贝,就像在使用原始指针,引用计数+1
最安全的分配和使用动态内存的方法是调用make_shared的标准库函数(工厂函数)
#include <memory>
shared_ptr<int> sp=make_shared<int>(10);
2.2 unique_ptr
某个时刻只能有一个unique_ptr指向一个给定对象,unique_ptr拥有它所指的对象,因此unique_ptr不支持普通的拷贝或赋值操作
#include <memory>
unique_ptr<int> up(new int(43)); //直接初始化
2.3 weak_ptr
weak_ptr 指向shared_ptr所指管理的对象,不控制对象生命周期。
不具有普通指针的行为,没有重载operator* 和 -> ,这是特意的,因为它不共享指针,不能操作资源,这是它“弱”的原因。
但它可以使用成员函数lock()从被观测的shared_ptr获得一个可用的shared_ptr对象,从而操作资源。
最大的作用是协助shared_ptr工作,像旁观者那样观测资源的使用情况。
用法:
#include <memory>
shared_ptr<int> sp(new int(43));
weak_ptr<int> wp(sp);
if(!wp.expired()){
shared_ptr<int> sp2=wp.lock(); //sp引用计数+1
*sp2=100;
}//退出作用域后,sp2析构,sp引用计数-1
3. pool库
boost.pool库,有4个组成部分:
内存池 pool
分配类实例的对象池 object_pool
单件内存池 singleton_pool
可用于标准库的 pool_alloc
3.1 内存池 pool
内存池:预先分配一块大的内存空间,然后就可以在其中使用某种算法实现高效快速的自定制内存分配。
pool库,返回一个简单数据类型(POD)的内存指针。
#include <boost/pool/pool.hpp>
using namespace boost;
#include <iostream>
int* pool_test(pool<> &pl)
{
int *p = (int*)pl.malloc(); //分配
*p = 13;
std::cout << *p << std::endl;
return p;
}
int main()
{
pool<> pl(sizeof(int)); //一个可分配Int的内存池
//std::cout << pl.get_max_size() << std::endl;
int *p = pool_test(pl);
std::cout << *p << std::endl;
pl.free(p); //释放
//std::cout << *p << std::endl;
for (int i = 0; i < 100; i++){ //连续分配大量的内存
pl.ordered_malloc(10);
}
} //退出作用域后,内存池对象析构,所分配的内存在这里都被释放。
3.2 对象池 object_pool
对象池功能与内存池类似,但会在析构时对所有已经分配的内存块调用析构函数,从而正确的释放资源。
boost::object_pool类摘要
// In header: <boost/pool/object_pool.hpp>
template<typename T>
class object_pool : protected boost::pool {
public:
// types
typedef T element_type; // ElementType.
//struct/copy/destruct
explicit object_pool();
~object_pool();
// public member functions
element_type * malloc();
void free(element_type *const);
//malloc()和free()函数用于分配和释放一块类型为ElementType* 内存块,
//但并不调用类的构造函数和析构函数,也就是说操作的是一块原始内存块,里面的值是未定义的,
//尽量少使用
bool is_from(element_type *const) const;
element_type * construct();
void destroy(element_type *const);
//这两个函数是object_pool的真正价值所在。
//construct()先调用malloc()分配内存,然后在内存块上调用类的构造函数,返回一个已经初始化的对象指针。
//destroy()则先调用对象的析构函数,然后再free()释放内存
};
使用:
#include <boost/pool/pool.hpp>
using namespace boost;
#include <iostream>
class ClassName
{
public:
ClassName(int m, int n) :a(m), b(n){}
int a;
int b;
};
void object_pool_test()
{
object_pool<ClassName> op;
ClassName* p = op.construct(13, 5);
std::cout << p->a <<" "<< p->b << std::endl;
} //退出时,所有创建的对象都被正确的析构,释放内存。
3.3 单件池 singleton_pool
#include <boost/pool/singleton_pool.hpp>
using namespace boost;
#include <iostream>
//struct pool_tag{}; //仅仅用于标记的空类
//typedef singleton_pool<pool_tag, sizeof(int)> spl; //内存池定义
//内存池定义:直接在模板参数列表中声明tag类,这样可以在一条语句中完成对singleton_pool的类型定义。
typedef singleton_pool<struct pool_tag, sizeof(int)> spl;
void singleton_test()
{
int *p = (int*)spl::malloc(); //分配一个整数内存块
//assert(spl::is_from(p));
spl::release_memory(); //释放所有未分配的内存
*p = 13;
std::cout << *p << std::endl;
} //sql的内存直到程序结束才释放,而不是退出作用域。