2009-03-25 11 views
3
文は以下からである

、ブルース・Eckel氏によるThe Positive Legacy of C++ and Java、C++で演算子オーバーロードについて:演算子のオーバーロードにメモリが割り当てられていますか?

C++は、両方のスタック割り当てとヒープ 割り当てを持って、あなたはすべての状況と ではなく処理するために、あなたの 演算子をオーバーロードする必要がありますメモリリークを引き起こします。確かに難しい 。

オペレータのオーバーロードがメモリ割り当てとどのように関係しているかわかりません。誰も彼らがどのように相関しているか説明できますか?

+0

私はC++で作業していません。しかし、演算子をオーバーロードすると、新しい値を返す必要があります(単純な値の場合はスタックに、複雑な型の場合はヒープ上にある可能性があります)。ペルソナ;人* b;人* c = a + b; – shahkalpesh

答えて

3

まず、newdelete ++ Cの両方で実際に演算子です。これらの演算子をオーバーロードすることによってオブジェクトのカスタム割り当て動作を提供することを選択した場合は、リークを導入しないように注意する必要があります。

第2に、オブジェクトのタイプによっては、メモリ管理のバグを避けるためにをオーバーロードする必要があります。たとえば、スマートポインタオブジェクト(Boost shared_ptrなど)をカウントするリファレンスがある場合は、operator=を実装する必要があります。正しく実行する必要があります。この壊れた例を考えてみましょう:それはmDataother.mData上の参照カウントを管理していないため、ここで

template <class T> 
class RefCountedPtr { 
public: 
    RefCountedPtr(T *data) : mData(data) { mData->incrRefCount(); } 
    ~RefCountedPtr() { mData->decrRefCount(); } 
    RefCountedPtr<T>& operator=(const RefCountedPtr<T>& other) { 
     mData = other.mData; 
     return *this; 
    } 
    ... 
protected: 
    T *mData; 
}; 

operator=実装が壊れている:それは漏れにつながる、mDataの参照カウントをデクリメントしません。 other.mDataの参照カウントをインクリメントしないので、実際の参照がすべて消える前に、指し示されているオブジェクトが削除される可能性があるため、メモリフォルトが発生する可能性があります。

クラスに独自のoperator=を明示的に宣言しないと、コンパイラはここに示す実装と同じ振る舞いを持つデフォルト実装を提供します。つまり、この特定のケースでは完全に壊れています。

記事によれば、オペレータに過負荷をかけなければならない場合があり、すべての状況を正しく処理するように注意する必要があります。

EDIT:申し訳ありませんが、参考文献が本ではなくオンラインの記事であることはわかりませんでした。完全な記事を読んだ後でさえ、何が意図されているかははっきりしないが、私はEckelがおそらく上記の2番目のような状況を指していたと思う。

+0

それは記事です...ただリンクをクリックしてください – yesraaj

+0

記事は実際には多くの文脈を提供しませんでした - 私はエリックが記事で言及された本について話していたと思われます –

0

演算子は関数です。彼らが構文的な砂糖を加えているからといって、あなたが記憶に注意する必要はありません。他のメンバ/グローバル/フレンド関数と同様にメモリを管理する必要があります。

これは、ラッパーポインタークラスを実装するときにオーバーロードするときに特に重要です。

operator+またはoperator+=をオーバーロードすることによって文字列の連結が行われます。詳細についてはbasic_stringテンプレートをご覧ください。

私はカップルの解釈の可能性を想像することができます
1

実際にはC++の演算子であり、独自のカスタマイズされたメモリ管理を提供するためにオーバーライドすることができます。exampleをご覧ください。

0

JavaとC++の間の演算子のオーバーロードを比較する場合、newdeleteについては言及しません。Javaでは、新しいメモリ管理の詳細が十分に公開されていないため、削除する必要はありません。

他の演算子をポインタ型にオーバーロードすることはできません。少なくとも1つの引数はクラスまたは列挙型でなければならないため、ポインタに対して異なる演算子を提供することについては言及できません。

C++の演算子は、値または値のconst参照を処理します。

オペレータがvalueまたはconstの値を参照することによって、値以外のものが返されることは非常に珍しいことです。

すべてのC++関数に共通の明白なエラーは別として、スタックに割り当てられたオブジェクトへの参照を返す(メモリリークの反対)か、値ではなくnewで作成されたオブジェクトへの参照を返します通常、学習する前にキャリアで一度も行われていない)、一般的な演算子が記憶上の問題を抱えているシナリオを思いつくのは難しいでしょう。

したがって、オペランドが通常の使用パターンに基づいてスタックまたはヒープに割り当てられているかどうかによって、複数のバージョンを作成する必要はありません。

オペレータへの引数は、値または参照として渡されるオブジェクトです。 C++には、オブジェクトがヒープまたはスタックに割り当てられたかどうかをテストするための移植可能なメカニズムはありません。オブジェクトが値渡しされた場合は、常にスタックに格納されます。したがって、2つのケースの演算子の振る舞いを変更する必要がある場合は、C++で移植可能ではありません。 (多くのOSでは、オブジェクトへのポインタがスタックに通常使用されているスペースにあるのか、通常はヒープに使用されているスペースにあるのかをテストできますが、ポータブルでも信頼できるものでもありません。 2つのポインタを引数として取ったので、オブジェクトがポインタであるためにヒープが割り当てられていると信じる理由はありません

唯一の重複は、演算子[ ]ここで、同じ演算子はアクセサーとミューテータの両方として使用されます。 constと非constバージョンを持つことは普通です。したがって、受信者がconstでない場合は値を設定できます。これは良いことです - 定数としてマークされているオブジェクト(公開されている状態)を変更することはできません。

関連する問題