2012-02-12 24 views
1

C++で演算子newdeleteを使用するのは楽しいですが、後でプログラムのコードでdeleteを呼び出すときに問題が発生することがよくあります。クラスnewとdelete演算子でメモリリークを処理するC++

たとえば、次のコードで:

class Foo { 
public: 
    string *ace; 
    Foo(); 
    ~Foo(); 
}; 
Foo::Foo() { 
    ace = new string; 
} 
Foo::~Foo() { 
    delete ace; 
} 
void UI::ButtonPressed() { //Happens when an event is triggered 
    Foo *foo = new Foo; 
    ui->label = ace; //Set some text on the GUI 
    delete foo; //Calls the destructor, deleting "ace" and removing it from the GUI window 
} 

Iはnew文字列を宣言することができるが、私はそれをdelete場合、その文字列が現在削除されているので、それはGUIフォームから値を除去します。

私は後で何とかこの割り当てられた文字列を削除するための方法はありますか?

私は、プログラムのソースコードの最後の行に、それをグローバル変数として宣言してからdeleteする必要はありません。私はちょうどdeleteと呼ぶことはできませんでしたが、私が教えていることから、それは悪いことであり、メモリリークを引き起こします。

+0

'std :: string'は異なる場合がありますので、 std :: string ace; 'スマートポインタなどについてもっと学ぶべきでしょう。http://en.wikipedia.org/wiki/Smart_pointer –

+0

スマートポインタが非標準のC++データ型で動作するかどうかを知りますか? 'QString'(QT)など? – user99545

+0

Qtにはある種のスマートポインタもありますし、 'std :: smart_ptr'などです。 Qtで動作するはずです... –

答えて

1

RAII patternについてお読みください。これは、C++プログラマを知る上で最も重要な概念の1つです。

基本的な考え方は、リソースの寿命(new'edオブジェクト、HTTP接続など)オブジェクトの寿命に接続されることです。これは、例外安全なコードを書くために必要です。あなたのケースでは

、UIウィジェットは、オブジェクトのコピーを作成し、独自のデストラクタでそれを解放します。呼び出しコードは、すぐに(別のデストラクタで)そのコピーを解放することができます。

+0

RAIIのパターンを教えてくれてありがとう、すばやく調査した後、私の質問にすべて答えました。 – user99545

1

あなたはaceui->labelの両方のためのstd::stringを使用している場合fooオブジェクトがスコープの外に出た後、あなたはfoo->acedelete Dであることのためのメモリを心配する必要はありません。

ui->labelには=(割り当て操作)のRight-Hand引数のコピーが用意されています。詳細については、C++ std::string reference page for string::operator=を参照してください。

はまた、このような問題は、このようなboost libraryが提供するものとして、スマートポインタを使用することによって、完全な回避することができます。より良い理解を得るためにこの件に関するthis great postをstackoverflowで読んでください。ここで

0

は、より多くの慣用的なC++プログラムです:あなた本当には、常に適切なスマートポインタを使用、newを呼び出す必要がある場合

class Foo { 
public: 
    std::string ace; 

    Foo() : ace() { 
     // nothing to do here. ace knows how to create itself… 
    } 

    // and copy itself… 
    Foo(const Foo& other) : ace(other.ace) {} 

    // and clean up after itself… 
    ~Foo() { 
    } 

    // and copy/assign itself… 
    Foo& operator=(const Foo& other) { 
     this->ace = other.ace; 
     return *this; 
    } 
}; 


void UI::ButtonPressed() { 
    // `new` is not needed here, either! 
    Foo foo; 
    ui->label = foo.ace; //Set some text on the GUI 
    // `delete` is not needed here 
} 

からdeleteは、現代のC++から追放された書き込みを;)まあ

1

あなたのコードについて多くのことが言えます。いくつかのことは既に述べられている。割り当て/ deallcoationの問題が完全に消えるので、あなたは、文字列、通常のメンバーにする必要があること(つまり、C++プログラムのための一般的なルールです:あなたは絶対にないとは、期間を、その後、使用動的割り当てする必要はありません)。また、適切なスマートポインタを使用すると、メモリ管理が行われます(C++の一般的なルールでもあります。本当に必要な場合を除いて、自分で動的割り当てを管理しないでください)。

ただし、ダイナミックアロケーションを使用する必要があり、生ポインタを使用してnewdeleteを直接使用する必要があるとしましょう。次に、別の重要なルールが入ります(実際にはC++固有のルールではありませんが、一般的なオブジェクト指向のルールです)。メンバーをパブリックにしないでください。プライベートメンバーにして、それを設定するためのパブリックメンバー関数を提供します。そのパブリックメンバ関数は、新しいオブジェクトにポインタを割り当てる前に、古いオブジェクトを適切に削除することができます。ポインタを割り当てた直後に、古い値を他の場所に保存していない限り、古い値は永遠に失われます。オブジェクトがそれまでに削除されていない場合は、後で削除することはできません。

また、あなたが渡したオブジェクトの所有権をポインタで取得して(デストラクタで削除されているポインタメンバに割り当てる)ことをお勧めしますか?です。所有権を渡す方法)。所有権を主張するオブジェクトに特定のオブジェクトを渡したかどうかを覚えておく必要があるため、これはオブジェクトの存続期間管理を複雑にします(ただし、という厳密なポリシーがある場合は常にが所有権主張オブジェクトに渡されます)。いつものように、スマートポインタがここで助けてくれるかもしれません。ただし、渡されたオブジェクトのコピーを作成する方が良いかどうかを検討することができます(std::stringは確かですが、ここでは前述のようにダイレクトメンバを持つ方が良いでしょう)。

だからここにそれを使用しないように十分な理由がありますしない限り、以前のルールは後でに優先し、ルールの完全なリスト、です:

  1. は、動的割り当てを使用しないでください。
  2. スマートポインタによる動的割り当てを管理します。
  3. コンストラクタでのみnewを使用し、対応するデストラクタでのみdeleteを使用してください。
  4. 同じクラスのメンバー関数内の特定のポインタには、常にnewdeleteがあります。 (実際のところ、前の規則はこの特殊なケースですが、一般的なものに優先する特殊なケースです)。
関連する問題