C++——auto_ptr类
http://blog.csdn.net/shineHoo/article/details/5195569
auto_ptr 類是一個模板類,它被定義在 memory 頭文件中。
auto_ptr 類可以用于管理由 new 分配的單個對象,但是無法管理動態分配的數組(我們通常不會使用數組,而是使用 vector 代替數組)。auto_ptr 在拷貝和賦值的時候有不尋常的行為,因此 auto_ptrs 不能被保存在 stl 的容器中。當 auto_ptr 離開了自己的作用域或者被銷毀,由 auto_ptr 管理的對象也會被銷毀。
1. 為異常安全的內存分配(Exception-Safe Memory Allocation)使用 auto_ptr
我們看下面的代碼:
void Func()
{
? int *pNum = new int(100);
? // code that throws an exception this is not caught inside Func
? delete pNum;
}
我們可以看到,假定在 new 和 delete 之間拋出了一個未捕獲的異常,那么內存泄漏發生了,delete pNum 未被執行。這就是非異常安全的內存分配。同樣還有一個類似的例子:
void Func()
{
? CMember* pMember = new CMember;
? CTeam* pTeam = QueryTeam(idTeam);
? if (NULL == pTeam)
? return; // Memory leaked
? pTeam->Add(pMember);
}
我們可以看到在動態分配了一個 CMember 對象后,由于出現某種情況函數 return,而 CMember 對象卻沒有得到釋放。
假如我們使用 auto_ptr 類代替,那么內存將會被自動釋放:
void Func()
{
? auto_ptr<int> ap(new int(100));
? // …
}
2. 綁定 auto_ptr 到一個指針:
通常的情況,我們這樣使用 auto_ptr 類:
auto_ptr<CClass> pObject(new CClass);
這樣,我們就完成了 auto_ptr 到指針的綁定。注意,以下這種表達是錯誤的:
auto_ptr<CClass> pObject = new CClass;
當 auto_ptr 離開自己的作用域時,綁定在 auto_ptr 上的指針指向的對象將被釋放。
3. 使用 auto_ptr
auto_ptr 類重載了解引用操作符(*)和箭頭操作符(->),這樣,我們能夠想使用內置指針一樣的使用 auto_ptr,例如:
class CClass
{
public:
? void Print();
? // …
}
int main()
{
? std::auto_ptr<CClass> pObj(new CClass);
? pObj->Print(); // the same (*pObj).Print();
}
4. auto_ptr 的賦值和拷貝操作符
內置的指針和 auto_ptr 的區別在于賦值和拷貝,這個需要特別注意。如果是內置指針的拷貝(賦值),那么結果是這兩個指針指向同一個對象,而 auto_ptr 則不一樣:
auto_ptr<string> ap1(new string("Stegosaurus");
auto_ptr<string> ap2(ap1);
執行完上面的語句后,ap1 將處于非綁定(unbound)狀態,并不指向任何對象,被管理的指針的所有權從 ap1 轉到 ap2,即指針將被 ap2 管理(包括內存的釋放等),而不是 ap1。
std::auto_ptr<std::string> ap1(new std::string("Pterodactry"));
std::auto_ptr<std::string> ap2;
如果是:ap2 = ap1, 則ap1指向NULL, ap2指向ap1所指的內容
如果是:ap1 = ap2; //ap1和ap2均指向NULL,注意此時所有資源已經被釋放。?
正是因為拷貝和賦值會破壞右操作數,所以 auto_ptrs 無法存儲在stl 的容器中。stl 的容器需要兩個對象在拷貝或者賦值之后相等。
?
5. auto_ptr 類的函數
1)默認構造函數
auto_ptr<int> pNum; // 沒有指向任何對象
*pNum = 100; // 錯誤
2)get 函數,返回指向對象的指針
if (NULL == pNum.get()) // 指針是否為空
注意,對于處于非綁定狀態的 auto_ptr 調用 get 將返回 0。不要做這樣的操作:
auto_ptr<int> pNum2(pNum1.get()); // 沒有轉交所有權
那么 pNum1 管理的指針將被析構兩次,這必然帶來嚴重的后果。
例如:
? ? auto_ptr<int> p1(new int(3));
? ? auto_ptr<int> p2(p1.get());
資源將被釋放兩次,會有嚴重問題。
3)reset 函數,重設需要管理的指針,首先 auto_ptr 會刪除當前管理的對象,然后再設置新的對象的指針。另外:
pNum = pNum; // 不會發送任何事情,安全
pNum.reset(pNum->get()); // 不會發送任何事情,安全。http://blog.csdn.net/sunmenggmail/article/details/8178984
//這是因為在reset中有判斷,內部指針是否等于外邊指針。
4)release 函數釋放所有權,返回它管理的指針,不刪除指針指向的對象:
auto_ptr<int> pNum2(pNum1.release()); // 等同于下句。
auto_ptr<int> pNum2(pNum1); // 等同于上句
6. 編譯器的問題
vc6 下的 auto_ptr 并不是標準的,例如:
std::auto_ptr<std::string> ap1(new std::string("Pterodactry"));
std::auto_ptr<std::string> ap2(ap1);
std::cout << *ap2 << std::endl; // 正常執行
7. 被管理的類的析構函數
如果被管理的類的析構函數為私有的,那么將無法使用 auto_ptr。?
?
補充:?
?
?
1.auto_ptr只能用于防止資源泄漏.也就是說是用auto_ptr的唯一目的在于使一個對象必然被delete.無論發生什么情況,這個對像都將在某個時候被釋放,而不會泄漏.所以,下面直接將auto_ptr所控制的對象成為資源.
2.auto_ptr理論上沒有引用計數的能力.所以所有依賴于引用計數的特性auto_ptr都不具備.例如:auto_ptr不能處理"野指針"的問題。
3.auto_ptr對象總是認為自己是所包含的資源的唯一擁有者.這導致:
? 3.1)一個auto_ptr對象被析構時,如果其持有一個有效的資源,那么這個資源必然被立即delete
? 3.2)一個auto_ptr對象被復制(賦值/拷貝構造/參數傳遞/函數返回)時:
???? 3.2.1)目標auto_ptr中原有的資源(如果有),必然被立即delete.
???? 3.2.2)目標auto_ptr獲得源auto_ptr原來所持有的資源.
???? 3.2.3)源auto_ptr失去其所持有的資源,成為一個空閑的對象.
4.auto_ptr作為函數的參數和返回值的時候,要特別注意,形參和實參的結合過程中存在auto_ptr的復制.從而導致資源控制權的轉移.從下面的一段代碼可以看出問題的嚴重性:
1: //這是一個危險的用法 2: template <class T> 3: void bad_print(std::auto_ptr<T> p) //形參P獲得了資源的控制權 4: { 5: //檢測p是否持有一個資源 6: if (p.get() == NULL) { 7: std::cout << "NULL"; 8: } 9: else { 10: std::cout << *p; 11: } 12: } //函數退出的時候,p的作用域結束.資源也就被釋放了.5.關于const auto_ptr,const auto_ptr意味著這個auto_ptr對象 永遠而且只能 持有這個資源.這意味著:
? 5.1)不能將一個const auto_ptr賦值給其它auto_ptr.(這一點和其他對象有很大的不同.而且直接導致auto_ptr不能被放到STL的容器中去).
? 5.2)可以使用const auto_ptr&作為參數類型來傳遞資源,而不會導致資源被意外delete.
? 5.3)被持有的資源本身可以被修改.
6.auto_ptr作為成員變量,也可以用這種方法來防止資源泄漏.但是需要注意對auto_ptr的控制權問題.這涉及到
???? 6.1)拷貝構造函數和賦值操作符重載.是否真的轉移控制權還是讓兩個auto_ptr都控制同一個對象? 多個auto_ptr控制同一個對象極容易導致野指針.
???? 6.2)是否有函數返回了此auto_ptr.一般應該直接返回此資源,同時要保證此資源沒有被其他auto_ptr控制,同時要保證在此auto_ptr所在的對象被銷毀后,沒有人會再使用此資源.
???? 6.3)最好是作為const auto_ptr來使用.
7.總結:
??? 1.盡可能只將auto_ptr對象作為一個函數的局部變量使用;
??? 2.如果一個大函數重構導致某個auto_ptr需要在多個函數中使用,通過const auto_ptr&方式直接傳遞過去;
??? 3.永遠不要返回auto_ptr對象,如果一定要這么用,就返回 const auto_ptr&,如果const auto_ptr&不能滿足要求,修改你的設計.
??? 4.不要將auto_ptr放到任何容器中去.當然 我們可以用類似于vector<auto_ptr<Object>*>這么來用.但是很無聊.
??? 5.將auto_ptr作為成員變量要慎重. 如果有此需要google以下其它帶有引用計數的智能指針吧.
?
?
最后,附上 SGI 的 auto_ptr 源碼:
template <class _Tp> class auto_ptr {
private:
? _Tp* _M_ptr;
public:
? typedef _Tp element_type;
? explicit auto_ptr(_Tp* __p = 0) __STL_NOTHROW : _M_ptr(__p) {}
? auto_ptr(auto_ptr& __a) __STL_NOTHROW : _M_ptr(__a.release()) {}
#ifdef __STL_MEMBER_TEMPLATES
? template <class _Tp1> auto_ptr(auto_ptr<_Tp1>& __a) __STL_NOTHROW
? : _M_ptr(__a.release()) {}
#endif /* __STL_MEMBER_TEMPLATES */
? auto_ptr& operator=(auto_ptr& __a) __STL_NOTHROW {
? if (&__a != this) {
? delete _M_ptr;
? _M_ptr = __a.release();
? }
? return *this;
? }
#ifdef __STL_MEMBER_TEMPLATES
? template <class _Tp1>
? auto_ptr& operator=(auto_ptr<_Tp1>& __a) __STL_NOTHROW {
? if (__a.get() != this->get()) {
? delete _M_ptr;
? _M_ptr = __a.release();
? }
? return *this;
? }
#endif /* __STL_MEMBER_TEMPLATES */
? // Note: The C++ standard says there is supposed to be an empty throw
? // specification here, but omitting it is standard conforming. Its?
? // presence can be detected only if _Tp::~_Tp() throws, but (17.4.3.6/2)
? // this is prohibited.
? ~auto_ptr() { delete _M_ptr; }
? _Tp& operator*() const __STL_NOTHROW {
? return *_M_ptr;
? }
? _Tp* operator->() const __STL_NOTHROW {
? return _M_ptr;
? }
? _Tp* get() const __STL_NOTHROW {
? return _M_ptr;
? }
? _Tp* release() __STL_NOTHROW {
? _Tp* __tmp = _M_ptr;
? _M_ptr = 0;
? return __tmp;
? }
? void reset(_Tp* __p = 0) __STL_NOTHROW {
? if (__p != _M_ptr) {
? delete _M_ptr;
? _M_ptr = __p;
? }
? }
? // According to the C++ standard, these conversions are required. Most
? // present-day compilers, however, do not enforce that requirement---and,?
? // in fact, most present-day compilers do not support the language?
? // features that these conversions rely on.
??
#if defined(__SGI_STL_USE_AUTO_PTR_CONVERSIONS) && /
? defined(__STL_MEMBER_TEMPLATES)
public:
? auto_ptr(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW
? : _M_ptr(__ref._M_ptr) {}
? auto_ptr& operator=(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW {
? if (__ref._M_ptr != this->get()) {
? delete _M_ptr;
? _M_ptr = __ref._M_ptr;
? }
? return *this;
? }
? template <class _Tp1> operator auto_ptr_ref<_Tp1>() __STL_NOTHROW?
? { return auto_ptr_ref<_Tp1>(this->release()); }
? template <class _Tp1> operator auto_ptr<_Tp1>() __STL_NOTHROW
? { return auto_ptr<_Tp1>(this->release()); }
#endif /* auto ptr conversions && member templates */
};
轉載自:http://blog.csdn.net/xkyx_cn/archive/2009/03/05/3960569.aspx
???????????http://www.cnblogs.com/zhuliangxiong/archive/2009/10/10/1580419.html
總結
以上是生活随笔為你收集整理的C++——auto_ptr类的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Divide a list of num
- 下一篇: vs2008 使用Visual Leak