RAII机制
为了管理内存等资源,C++程序员通常采用RAII机制(资源获取即初始化,Resource Acquisition Is Initialization ),在使用资源的类的构造函数中申请资源,然后使用,最后在析构函数中释放资源。
如果对象是在栈上创建的,RAII机制可以正常工作;但如果对象是使用new在堆上创建的,那么析构函数不会自动调用,程序员必须明确使用delete来释放资源。
智能指针
boost.smart_ptr库提供了6种智能指针:
- scoped_ptr
- shared_ptr
- intrusive_ptr
- weak_ptr
- scoped_array
- shared_array
使用方法
#include <boost/smart_ptr.hpp>
using namespace boost;
scoped_ptr
scoped_ptr的所有权很严格,不能转让,一旦scoped_ptr获取了对象的管理权,你就无法再从它那里取回来。
scoped_ptr<string> sp( new string( "text" ) );
cout << *sp << endl;
cout << sp->size() << endl;
sp++; // wrong, scoped_ptr未定义递增操作符
scoped_ptr<string> sp2 = sp; //wrong, scoped_ptr不能拷贝构造
struct poxist_file {
posix_file( const char* file_name ) {
cout << "open file: " << file_name << endl;
}
~posix_file() {
cout << "close file" << endl;
}
}
int main() {
scoped_ptr<int> p( new int );
if( p ) {
*p = 100;
cout << *p << endl;
}
p.reset();
assert( p == 0 );
if( !p ) {
cout << "scoped_ptr == null" << endl;
}
// 将在离开作用域时自动析构,从而关闭文件释放资源
scoped_ptr<posix_file> fp( new posix_file( "/tmp/a.txt" ) );
} // p和fp的指针自动被删除
result:
100
scoped_ptr == null
open file: /tmp/a.txt
close file
scoped_array
scoped_array很像scoped_ptr,包装了new[]操作符,它为动态数组提供了一个代理,保证内存正确释放。
int main() {
int* arr = new int[ 100 ];
scoped_array<int> sa( arr );
fill_n( &sa[ 0 ], 100, 5 );
sa[ 10 ] = sa[ 20 ] + sa[ 30 ];
}
如果可以使用STL的话,在需要动态数组的情况下我们使用std::vector,它比scoped_array提供了更多的灵活性,而只付出了很小的代价。
shared_ptr
shared_ptr是实现了引用计数的智能指针,可以被自由地拷贝和赋值,在任意的地方共享他,当没有代码使用(引用计数为0)时才删除被包装的动态内存。
shared_ptr<int> sp( new int( 10 ) );
assert( sp.unique() );
shared_ptr<int> sp2 = sp;
assert( sp == sp2 && sp.use_count() == 2 );
*sp2 = 100;
assert( *sp == 100 );
sp.reset();
assert( !sp );
class shared {
private:
shared_ptr<int> p;
public:
shared( shared_ptr<int> p_):p( p_ ) {}
void print() {
cout << "count:" << p.use_count() << "v = " << *p << endl;
}
};
void print_func( shared_ptr<int> p ) {
cout << "count:" << p.use_count() << " v =" << *p << endl;
}
int main() {
shared_ptr<int> p( new int( 100 ) );
shared s1( p ), s2( p );
s1.print();
s2.print();
*p = 20;
print_func( p );
s1.print();
}
注意,print_func()的参数是值传递,没有使用引用,所以最后输出如下:
count: 3 v = 100
count: 3 v= 100
count: 4 v= 20
count: 3 v = 20
工厂函数
shared_ptr的构造需要使用new,这导致了代码的不对称性(不需要使用delete),shared_ptr提供了一个工厂函数make_shared()来消除显式的new调用。
#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;
// using boost.foreach
for( auto& ptr : v ) {
ptr = make_shared< int >( ++i );
cout << *ptr << ", ";
}
}