智能指針(smart pointer):
智能指針是其實是一個對象A,它帶有一個模針成員變量m_p.用該A管理m_p,通過這種管理機制,可以防止由於new而導致的內存泄漏.
智能指針對象在使用時像指針一樣.同時也具有一般對象的所有特徵.如果要注意以下幾點:
1,對象之間的賦值:若有A=B,則在賦值時,
首先要鬆查是否爲自身賦值.如果不是,則釋放A對象成員指針的內存空間,
然後要將B中的成員指針賦值於A的成員指針,
接着將B中的成員指針置爲空,這樣可以避免多個指針同時指向一個內存空間而產生多次析構此內存空間的錯誤.
所以,重載的賦值函數一般如下:
operator =(Test& source_object); 此處不能爲const 對象的引用,這是因爲要修改source_object 的成員指針爲空.
2,對於copy constroctor也有與operator=類似的情況.只不過不要釋放A成員指針的內存空間,.
3,關於member template的問題,它往往用於兼容模板對象之間的相互賦值,copy constroctor.我們可以將它看成是個模板類(一個類).
譬如:auto_ptr<B>,這就是一個類名稱
另:VC7.0中,成員模板的定義和實現必須放在類的定義中.
注:member template不能爲static 或virtual
4,智能指針中必須重載的幾個運算符: -> *
這樣做的目的就是將對象模仿成指針的行爲.
如下:
T* operator ->()
{return m_p;}
特別注意:
object->m_p;== (object.operator->())->m_p;
T& operator *()
{return *m_p;}
下面的程序演示smart pointer的基本使用:
#include"iostream"
using namespace std;
template<class T>
class auto_ptr
{
public:
auto_ptr( T *p=0)
{
m_p=p;
}
//由auto_ptr<T> 來複制構造該auto_ptr<T>對象.
auto_ptr(auto_ptr<T>& source_object)
{
m_p=(T*)( source_object.get());
source_object.m_p=0; //
}
//由auto_ptr<M>來構造該auto_ptr<T>對象.
template<class M>
auto_ptr(auto_ptr<M> &source_object) //此處的對象爲非const 對象的引用.
{
m_p=(T*)( source_object.get());
source_object.m_p=0; //
}
//析構....
~auto_ptr()
{
if (m_p!=0)
Release();
}
//由auto_ptr<T>賦值於auto_ptr<T>對象.
auto_ptr<T>& operator=(auto_ptr<T> &source_object)
{
Release();
m_p=(T*)(source_object.get());
return *this;
}
//由auto_ptr<M>賦值於auto_ptr<T>對象.
template<class M>
auto_ptr<T>& operator=(auto_ptr<M> &source_object)
{
Release();
m_p=(T*)(source_object.get());
return *this;
}
//delete m_p;
void Release()
{
if (m_p!=0)
delete m_p;
m_p=0;
}
T* get()
{
return m_p;
}
// from auto_ptr<T> convert to auto_ptr<M>
//聲明:1 由於上面提供從auto_ptr<M>構造auto_ptr<T>的構造函數.所以,在實際上,不必給出下面的隱式類型轉換函數.
// 2 VC不支持這個隱式轉換特性.
template<class M>
operator auto_ptr<M>()
//如果M和T類型不一致時,將無法進行自動的類型轉換.如:auto_ptr<int> 與auto_ptr<float>
{
return auto_ptr<M>(m_p);
//此處困惑:::
// return auto_ptr<M>(m_p); 這是more effective C++中的寫法,當執行此語句時,會構造出一個新auto_ptr<M>的對象,而this對象的m_p並未釋放.這樣兩個對象的m_p指向共一個變量,???
//應該這樣:
//temp auto_ptr<M>(get());
//Release();
//return temp;
}
T* operator ->()
{
return m_p;
}
const T* operator->() const
{
return m_p;
}
//此處注意爲T&,這樣可以實現左值.
T& operator *()
{
return *m_p;
}
const T& operator *() const
{
return *m_p;
}
public:
T *m_p;
};
class test
{
public:
test(int data)
{
m_data=data;
}
int& operator->()
{
return m_data;
}
operator int()
{
return m_data;
}
public:
int m_data;
};
class A
{
public:
A(int data)
{
m_data=data;
}
private:
int m_data;
};
class B:public A
{
public:
B(int data):A(data*2),m_data(data)
{
;
}
private:
int m_data;
};
class C:public A
{
public:
C(int data):A(data*3),m_data(data)
{
;
}
private:
int m_data;
};
void test_member_template(const auto_ptr<A>& source_object)
//此處一定要加const,因爲對象隱式轉換後生成的對象爲臨時對象.臨時對象的生存週期將不由程序員決定,其值不能被修改.
{
//source_object.get();
}
void test_member_template2(const auto_ptr<int>& source_object)
//此處一定要加const,因爲對象隱式轉換後生成的對象爲臨時對象.臨時對象的生存週期將不由程序員決定,其值不能被修改.
{
;
}
void main()
{
auto_ptr<C> object2(new C(3));
test_member_template(object2);
//將調用member template constructor 構造出auto_ptr<A> 對象.注意,函數執行後,將導致object2變爲爲空殼對象.要避免這種隱式的模板對象構造.
auto_ptr<test> object(new test(15));
int data=object.operator->()->m_data;
//等價於: data=object.operator->()->operator->();
cout<<data;
auto_ptr<int> object_int(new int(999));
auto_ptr<int> object_int_2(new int(333));
object_int_2=object_int; //operator =
object_float=object_int; //operator = by member template
test_member_template2(object_int); //copy constructor
test_member_template2(object_float);//call constructor by member template.
//注意,函數執行後,將導致object2變爲爲空殼對象.要避免這種隱式的模板對象構造.
cout<<*object_float<<endl;;
auto_ptr<float> object_2=object_float;
//此處調用 copy constructor
cout<<*object_2<<endl;
}