スマートポインタ--RAI

4098 ワード

インテリジェントポインタ:RAIはすべてResource Acquisition Is Initializationと呼ばれ、いくつかのオブジェクト向け言語での慣用です.RAIIはC++に由来し、Java,C#,D,Ada,Vala,Rustにも応用されている.この用法は,資源管理時の異常な安全性を解決するために提案されたものである.通常のポインタの指向性と参照性の機能を実現し、クラスのオブジェクト構築時にオブジェクトとプロファイルを初期化するときにリソースを解放する責任を負います.
RAIIは、リソースの有効期間とリソースを持つオブジェクトのライフ期間を厳格にバインドし、すなわち、オブジェクトのコンストラクション関数によってリソースの割り当て(取得)を完了し、同時にコンストラクション関数によってリソースの解放を完了することを要求している.このような要求の下で,オブジェクトが正確に解析できる限り,リソース漏洩の問題は起こらない.
異常セキュリティ:
1.異常を投げ出した後、資源を漏らさない
2.異常を投げ出した後、元のデータを悪化させない(例えば、正常なポインタが野生のポインタになる)
3.try catchを少なくします.try catchの量が大きいとコードロジックに影響します.コードが醜く混乱して優雅ではない
auto_ptrが行うことは,オブジェクトを動的に割り当て,オブジェクトが不要になったときに自動的にクリーンアップを実行することであり,管理権移行と考えられる.auto_ptrには深刻な欠陥があり、できるだけ使わないことをお勧めします.
//AutoPtr     
template 
class AutoPtr
{
public:
	AutoPtr( T* ptr)
		:_ptr(ptr)
	{}
	AutoPtr(AutoPtr & p)
	{
		this->_ptr = p._ptr;
		p._ptr = NULL;
	}
	~AutoPtr()
	{
		cout << "~AutoPtr()" << endl;
		delete _ptr;
	}
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}
	AutoPtr& operator=(AutoPtr& p)
	{
		if (this != &p)
		{
			delete this->_ptr;
			this->_ptr = p._ptr;
			p._ptr = NULL;
		}
		
		return *this;
	}

protected:
	T* _ptr;
};

scoped_ptrは、コピーできない(すなわち、宣言のみ、定義なし)より厳しい使用制限があります.これはscoped_ptrポインタは所有権を変換できません.
//ScopedPtr   ,   ,   
template 
class ScopedPtr
{
public:
	ScopedPtr(T* ptr)
		:_ptr(ptr)
	{}
	~ScopedPtr()
	{
		cout << "~ScopedPtr()" << endl;
		delete _ptr;
	}
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}
	//      operator=     ,   
protected:
	ScopedPtr (ScopedPtr& p);
	ScopedPtr& operator=(ScopedPtr& p);
	
protected:
	T* _ptr;
};

shared_ptrは、参照カウントを使用することで、複数のポインタ間でオブジェクトの所有権を共有する問題を解決し、コンテナの要素に対する要求を満たすため、コンテナに安全に入れることができます.欠点:ループ参照の問題
循環参照の例:
class B;
class A {
public:
    shared_ptr p;
};

class B {
public:
    shared_ptrp;
};
int main() {
while (true) {
shared_ptrpa(new A());
shared_ptr pb(new B());
pa->p = pb;
pb->p = pa;
}
return 0;
}

whileサイクルでは,まずスタックに2つのスマートポインタを構築し,それぞれ2つのスタックメモリを管理し,A,Bと記す.2つの付与文がshared_ptrでは,A,Bの参照カウントはいずれも2であるため,paとpbを解析した場合,それらの参照カウントはいずれも0に到達できず,ループ参照が発生しメモリリークが開始される.
//   
template 
class Delete
{
public:
	void operator()(T* ptr)
	{
		cout << "delete" << endl;
		delete ptr;
	}
};
template 
class DeleteArray
{
public:
	void operator()(T* ptr)
	{
		cout << "delete[]" << endl;
		delete[] ptr;
	}
};
template 
class Fclose
{
public:
	void operator()(T* ptr)
	{
		cout << "fclose" << endl;
		fclose(ptr);
	}
};
template 
class Free
{
public:
	void operator()(T* ptr)
	{
		cout << "free" << endl;
		free(ptr);
	}
};

//ShareaPtr      
template >
class SharedPtr
{
public:
	SharedPtr(T* ptr)
		:_ptr(ptr)
		, _Count(new int(1))
	{}
	~SharedPtr()
	{
		cout << "~SharedPtr()" << endl;
		Clear();
	}
	SharedPtr(SharedPtr & p)
		:_ptr(p._ptr)
		, _Count(p._Count)
	{
		++(*_Count);
	}
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}
	SharedPtr& operator=(SharedPtr & p)
	{
		if (this != &p)
		{
			Clear();
			_ptr = p._ptr;
			_Count = p._Count;
			++(*_Count);
		}
		return *this;
	}
	void Clear()
	{
		if (--(*_Count) == 0)
		{
			cout << "delete" << endl;
			//delete _ptr;
			_del(_ptr);
			delete _Count;
		}
	}

protected:
	T* _ptr;
	int* _Count;
	Del _del;
};

循環参照の解決:
weak_ptrはshared_に合わせるためですptrが導入したスマートポインタはshared_を支援するptrはshared_から動作しますptrまたは別のweak_ptrオブジェクト構造は、参照記数の増加または減少を引き起こさない構造および析出構造である.リロード*と->はありませんが、lockを使用して使用可能なshared_を取得できます.ptrオブジェクト