用法一:
std::auto_ptr<ClassName>m_example(new ClassName ());
用法二:
std::auto_ptr<ClassName >m_example;
m_example.reset(new ClassName());
用法三(指針的指派操作):
std::auto_ptr<ClassName>m_example1(new ClassName());
std::auto_ptr<ClassName>m_example2(new ClassName());
m_example2=m_example1;
auto_ptr會自動釋放記憶體,則C++會把m_example所指向的記憶體回收,使m_example1 的值為NULL,是以在C++中,應絕對避免把auto_ptr放到容器中:vector<auto_ptr<MyClass>>m_example; 當用算法對容器操作的時候,很難避免STL内部對容器中的元素實作指派傳遞,這樣便會使容器中多個元素被置位NULL。正确運用auto_ptr讓你的代碼更加安全,而對auto_ptr危險但常見的誤用會引發間斷性發作、難以診斷的bug,而auto_ptr隻是衆多可能的智能指針之一。許多商業庫提供了更複雜的智能指針,用途廣泛而令人驚異,從管理引用的數量到提供先進的代理服務。可以把标準C++ auto_ptr看作是一個簡易、通用的智能指針,它不包含所有的小技巧,不像專用的或高性能的智能指針。 模拟實作auto_ptr中指派運算符重載:
#include<iostream>
using namespace std;
template <class T>
class AutoPtr
{
public:
AutoPtr(T* ptr = NULL)
: _ptr(ptr)
{
cout << "AutoPtr()" << endl;
}
AutoPtr(AutoPtr &ap)
:_ptr(ap._ptr)//移交管理權
{
if (_ptr)
{
ap._ptr = NULL;
}
}
AutoPtr<T>& operator =(AutoPtr &ap)
{
if (this != &ap)
{
delete _ptr;
_ptr = ap._ptr;
ap._ptr = NULL;
return *this;
}
}
~AutoPtr()
{
if (_ptr)
{
cout << "~AutoPtr()" << endl;
delete _ptr;
_ptr = NULL;
}
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
protected:
T* _ptr;
};
void TestAutoPtr()
{
AutoPtr<int> ap1(new int);
*ap1 = 10;
AutoPtr<int> ap2 = ap1 ;
AutoPtr<int> ap3(new int(20));
ap2 = ap3;
}
int main()
{
TestAutoPtr();
system("pause");
return 0;
}
打開記憶體視窗就會發現将ap1指派給ap2之後ap1的空間也會釋放
auto_ptr特點:
1. 利用特點“棧上對象在離開作用範圍時會自動析構”。
2. 對于動态配置設定的記憶體,其作用範圍是程式員手動控制的,這給程式員帶來了友善但也不可避免疏忽造成的記憶體洩漏,畢竟隻有編譯器是最可靠的。 3. auto_ptr通過在棧上建構一個對象a,對象a中 包含了動态配置設定記憶體的指針p,所有對指針p的操作都轉為對對象a的操作。而在a的析構函數中會自動釋放p的空間,而該析構函數是編譯器自動調用的。 執行個體如下:
#include <iostream>
#include <memory>
using namespace std;
class A
{
public:
A()
{
cout<<"A()"<<endl;
}
~A()
{
cout<<"~A()"<<endl;
}
};
void fun(bool isThrow)
{
//A *pa= new A; // 方法1
//try
//{
// if(isThrow)
// throw " throw a date ";
//}
//catch(const char* e)
//{
//
// throw;
//}
auto_ptr<A> A(new A); // 方法2
try
{
if(isThrow)
throw "throw a date";
}
catch(const char* e)
{
throw;
}
}
int main()
{
try
{
fun(true);
}
catch(...)
{
cout<<"caught"<<endl;
}
system("pause");
}
如果采用方案1,那麼必須考慮到函數在因throw異常的時候釋放所配置設定的記憶體,這樣造成的結果是在每個分支處都要很小心的手動 delete A;。 如果采用方案2,那就無需操心何時釋放記憶體,不管fun()因何原因退出, 棧上對象A的析構函數都将調用,是以托管在之中的指針所指的記憶體必然安全釋放。 至此,智能指針的優點已經很明了了。 但是要注意使用中的一個陷阱,那就是指針的托管權是會轉移的。使用指派運算符重載操作後源變量指針就會變空,是以再用源指針調用就會出現問題。要避免這個問題,可以考慮使用采用了引用計數的智能指針,例如boost::shared_ptr等。auto_ptr不會降低程式的效率,但auto_ptr不适用于數組,auto_ptr根本不可以大規模使用。 shared_ptr也要配合weaked_ptr,否則會很容易觸發循環引用而永遠無法回收記憶體。
scopedptr
因為智能指針容易出現拷貝時釋放兩次的情況,是以ScopedPtr主要是進行防止拷貝,防止拷貝的兩條必須要滿足的條件是:
(1)設定保護限定符, (2)對拷貝構造函數和指派運算符重載進行之聲明不定義。 如若隻有(2),沒有設定保護限定符,若在類外進行定義後,則會出現問題,是以說這兩個條件是必不可少的。這樣就能夠避免上面所出現的問題,但是這樣就造成了它在功能上的缺陷。
//ScopedPtr 實作簡單的智能指針進行防拷貝
template <class T>
class ScopedPtr
{
public:
ScopedPtr(T * ptr)
:_ptr(ptr)
{ }
~ScopedPtr()
{
cout << "delete" << endl;
if (_ptr)
{
delete _ptr;
_ptr = NULL;
}
}
T & operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
T* GetPtr()
{
return _ptr;
}
protected: //防止拷貝
ScopedPtr(ScopedPtr<T> & ap);
ScopedPtr<T> & operator=(ScopedPtr<T> & ap);
private:
T * _ptr;
};
當調用拷貝構造和指派運算符重載時就會出現下面錯誤:
1>f:\程式\智能指針\智能指針\scopedptr.cpp(46) : error C2248: “ScopedPtr<T>::ScopedPtr”: 無法通路protected 成員(在“ScopedPtr<T>”類中聲明)