2011-12-20 3 views
12

私はC++に少し新しく、今までObj-CとJavaでプログラミングを行っていました。C++:メモリ管理について

言って、私はクラスを持っている:

class Person { 

private: 
    Wife *current_wife; 
    //..... 
}; 

は、だから私は、妻のインスタンス変数を変更するためにsetterメソッドを実装する必要がOBV。このよう

:shalllowコピーだろう

Person::SetCurrentWife (Wife *new_wife) { 

    current_wife = new_wife; 
} 

だから、どこかでメインループか何かから私が呼ん:

Person *some_person = new Person(); 
... 
Wife *wife = new Wife(); 
some_person->SetCurrentWife(wife); 

だから私は混乱している:ここでメモリリークがあるでしょうか?ここで、またはPersonのデストラクタで妻オブジェクトを削除すべきですか? Obj-Cでは、私は現在の妻を解放し、上記のオブジェクトにretainメッセージを送信しますが、C++でセッターメソッドを実行する正しい方法は何ですか?

+10

C++を初めて使ったので、このアドバイスに注意してください: 'new'、' delete'、またはポインタを使用しないでください。例外として、スマートポインタのコンストラクタの中で 'new'を使うかもしれませんが、あなたが実際にダイナミックストレージを必要とすると判断した後でなければなりません。 –

+4

Kerrekは[良い入門C++の本](http://stackoverflow.com/q/388242/46642)をお勧めしませんでした:) –

+4

OOでは、あなたはセッターが必要ではありません、オブジェクトに何かをさせる関数が必要です(離婚、再婚)。セッターは便利かもしれない、彼らはobvではない。 – stefaanv

答えて

4

スマートポインタを使用する必要があります。

通常のポインタを使用する場合は注意してください!

古いcurrent_wifeメンバーは、デストラクタと設定メソッドの両方でdeleteになる必要があります。新しい妻を設定すると、割り当てられたメモリへのポインタが失われるため、古いクラスのメモリリークが発生します(クラス外のメモリを管理しない限り - 以下を参照)。

でも、クラス外の誰もメンバーを削除できないようにする必要があります。メモリ管理がクラスに残っているのか、クラスの外部にディスパッチされているのかを判断し、それに固執する必要があります。

+3

-1これは単に悪いアドバイスだからです。スマートポインタが希望の生涯のセマンティクスを実装すれば、私は非常に驚くでしょう---あなたは本当に私の妻が死ぬことは不可能であるとは信じていません。 –

+0

@JamesKanzeだからこそなぜ問題になるのだろうか?スマートポインタを使用すると、あらかじめ妻のオブジェクトを削除したり、人が死んだ後に削除したりすることが制限されますか? –

+0

それはスマートポインタに依存しますが、標準のスマートポインタのいずれかで管理されているものを削除すると、未定義の動作になります。 'shared_ptr'を使うと、特に、オブジェクトの寿命はあなたの手から外れます。 –

1

スマートポインタは、あなたの

using boost::shared_ptr; // or std::shared_ptr, or std::tr1::shared_ptr or something like this 
class Person { 

private: 
    shared_ptr<Wife> current_wife; 
    //..... 
}; 

Person::SetCurrentWife (shared_ptr<Wife> new_wife) { 

    current_wife = new_wife; 
} 

を助けることができるそして今、あなたはまったく妻を削除しないでください。

shared_ptr<Person> some_person (new Person); 
... 
shared_ptr<Wife> wife (new Wife); 
some_person->SetCurrentWife(wife); 
+3

これは災害のレシピのようです。 'shared_ptr'が動作するケースはごくわずかですが、私はこれがそれらのものではないと考えています。理由は2つあります。まず、「妻」は自分が妻であることを知っている可能性が高いため、サイクルが必要です(妻に何か起こった場合、現在の配偶者に知らせなければならないのでサイクルが必要です)。第二に、「妻」の生涯は確かに配偶者の生涯に依存しない。「妻」が死亡した場合、配偶者が彼女の指針を維持しているからといって生きていてはならない。 –

+0

@JamesKanzeだから、私が推測すると 'boost :: weak_ptr'があるのです。これにより、サイクルを中断させ、死んだオブジェクトの安全な通知を可能にします。 – cheind

+0

@ChristophHeindlだから、どのポインタが弱くなければならないの? 'boost :: weak_ptr'はハックであり、一般的には使えません。 –

7

これは、実行しようとする内容によって異なります。まず、Kerrek SBに というコメントがあるので、値の意味が適用できる場合、ポインタを使用したくない場合 が適用されます。Wifeがコピー可能で割り当て可能な場合は、 を動的に割り当てる理由はほとんどありません。この場合は、しかし、私は Wifeもあるかもしれないこと、(おそらくPerson ためのデコレータは、与えられたPerson ISA Wifeが経時的に変化することができるという事実から、より適切であろうが)Personから派生したことを推測していますタイプ からWifePerson::current_wifeは のいずれかを保持したいかもしれません)、そして実際にはWifeは同一性を持ちます。あなたは のコピーをその場所のすべての同じ妻にはしたくありません。

この場合、他のクラスの 相互作用のプロトコルを実際にWifeで定義する必要があります。通常、 Wifeの有効期間は、 デコレータの場合でも、Personには依存しません。Personは、 のように、ポインタを保持するだけです。例えば

void Wife::die() 
{ 
    // ... 
    delete this; 
} 

:あなたは のようなものがあるかもしれません:ほとんどの場合、Wifeオブジェクトが—暗黙的または明示的に—制御その寿命様々な機能 を持つことになります。しかし、その場合は、Wifeと結婚した人は となるので、current_wifeは死亡者を指していません 配偶者。典型的には、オブザーバパターンのいくつかの変形を に使用することができる。 (。あなたはJavaで正確に同じ問題を持っていることに注意してください。あなたはまだ Wife::die()機能を必要があると思いますので、 がPerson::current_wifeが死んWifeを指すようにしたくない、と 配偶者に通知するためのオブザーバーパターン)

C++とJavaの間の唯一の違い については、このような場合(C++で動的に割り当てられたオブジェクトの大半 を表す私の経験である)、で

は、C++が “デストラクタ”を呼び出すための特別な構文を持っているということです。 Javaでは、通常の関数呼び出し の構文を使用します。関数には任意の名前を付けることができます( が広く使われているようですが)。特別な構文では、コンパイラは にメモリを解放するための追加コードを生成することができますが、オブジェクトライフタイムの終了に関連する他のすべてのアクティビティはまだ でなければなりません(デストラクタではC++で—、それは の一部を直接Wife::die 関数に入れることに意味があります)。