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