アセンブリの目から見るC++(deleteメモリ漏洩)
【声明:著作権所有、転載歓迎、商業用途に使用しないでください.連絡ポスト:[email protected]】
C言語のプログラミングをしたことがある人は、mallocメモリの後にfreeがメモリを落とさないと、メモリが漏れる可能性が高いことをよく知っています.では、C++の上にも、このような問題があるのではないでしょうか.その結果、C++の上にもメモリが漏れる危険性があります.この危険は、newの後ろにdeleteができなければ、メモリの漏洩を引き起こすことです.不明な方は以下の例をご覧ください.
では、このような定義があれば、私たちはどのように使うべきでしょうか.次の関数呼び出しを参照してください.
【予告:次のブログでは、クラスメンバーのポインタコピーについて説明します】
C言語のプログラミングをしたことがある人は、mallocメモリの後にfreeがメモリを落とさないと、メモリが漏れる可能性が高いことをよく知っています.では、C++の上にも、このような問題があるのではないでしょうか.その結果、C++の上にもメモリが漏れる危険性があります.この危険は、newの後ろにdeleteができなければ、メモリの漏洩を引き起こすことです.不明な方は以下の例をご覧ください.
class test
{
int data;
public:
test(int value):data(value) {}
~test() {};
};
void process()
{
test* t = new test(0);
if(/* some errors happens */)
{
return;
}
delete t;
return;
}
上のコードは、問題をある程度説明しています.実は上のコードは関数が戻るときにメモリ削除の問題を考慮していますが、errorが発生したときにタイムリーに処理しなければメモリが漏れることもあります.では、何かいい方法はありませんか.C++は、関数が終了したときに自動的にリソースの解放を完了することを保証する性質があるかどうかを見ることができます.はい、それが構造関数です.したがって、一般的には、追加のクラス定義を追加することができます.class auto_point
{
test* t;
public:
auto_point(test* p) : t(p) {}
~auto_point() { if(t) delete t;}
};
しかし、私たちの多くの操作はポインタに従って行われていましたが、クラスをポインタに変えるにはどうすればいいのでしょうか.では、演算子を使って再ロードするしかありません.class auto_point
{
test* t;
public:
auto_point(test* p) : t(p) {}
~auto_point() { if(t) delete t;}
test* operator->() { return t;}
const test& operator* () {return *t;}
};
では、このような定義があれば、私たちはどのように使うべきでしょうか.次の関数呼び出しを参照してください.
22: auto_point p(new test(0));
004010AD push 4
004010AF call operator new (00401300)
004010B4 add esp,4
004010B7 mov dword ptr [ebp-18h],eax
004010BA mov dword ptr [ebp-4],0
004010C1 cmp dword ptr [ebp-18h],0
004010C5 je process+56h (004010d6)
004010C7 push 0
004010C9 mov ecx,dword ptr [ebp-18h]
004010CC call @ILT+80(test::test) (00401055)
004010D1 mov dword ptr [ebp-1Ch],eax
004010D4 jmp process+5Dh (004010dd)
004010D6 mov dword ptr [ebp-1Ch],0
004010DD mov eax,dword ptr [ebp-1Ch]
004010E0 mov dword ptr [ebp-14h],eax
004010E3 mov dword ptr [ebp-4],0FFFFFFFFh
004010EA mov ecx,dword ptr [ebp-14h]
004010ED push ecx
004010EE lea ecx,[ebp-10h]
004010F1 call @ILT+65(auto_point::auto_point) (00401046)
004010F6 mov dword ptr [ebp-4],1
23: if(1/* some errors happens */)
004010FD mov edx,1
00401102 test edx,edx
00401104 je process+97h (00401117)
24: {
25: return;
00401106 mov dword ptr [ebp-4],0FFFFFFFFh
0040110D lea ecx,[ebp-10h]
00401110 call @ILT+75(auto_point::~auto_point) (00401050)
00401115 jmp process+0A6h (00401126)
26: }
27:
28: return;
00401117 mov dword ptr [ebp-4],0FFFFFFFFh
0040111E lea ecx,[ebp-10h]
00401121 call @ILT+75(auto_point::~auto_point) (00401050)
29: }
上記のコードからよくわかりますが、コードがいつ終了しても、関数はクラスの基本特性を利用してクラスの構造関数を自動的に呼び出し、さらにメモリが解放され、メモリ漏洩の問題は発生しません.しかし、上記のソリューションにも不足があることがわかりました.つまり、クラスごとに追加の定義クラスを追加定義する必要があります.では、この問題を解決する方法はありますか?それがテンプレートです.template <typename type>
class auto_point
{
type* t;
public:
auto_point(type* p) : t(p) {}
~auto_point() { if(t) delete t;}
test* operator->() { return t;}
const test& operator* () {return *t;}
};
私たちのタイプが特定でない場合は、使用時に特定のタイプに従って入力するだけです.【予告:次のブログでは、クラスメンバーのポインタコピーについて説明します】