2011-01-23 3 views
4

私はC++ Primer Plus by Stephen Frataを読んでいます。私は第6章まで読んだことがあります。これは、ポインタについて学んだことですが、オブジェクトやクラスについては学んでいないことを意味します(OOPについて知っていますが)。スマートポインタなしでポインタを処理するにはどうすればよいですか?

私は、ActionScript(フラッシュ)やJavaの背景から来たので、私は前にポインタを扱ったことがないが、私はそれを理解しています。私は彼らについての質問の束を持っています。

私が理解できるように、あなたはすなわち、ポインタはそれを解放する責任が作成したオブジェクト/機能、新しいペアおよび削除する必要があります。しかし、次のような簡単なファクトリ関数を想像してみてください。

SomeObject * createSomeObject(){ 
    return new SomeObject; 
} 

これはかなり問題があります。誰がこのポインタを解放する責任がありますか?

作成したポインタにパブリックアクセスできるクラスを作成するとどうなりますか?新しい/削除ルールに続いて、このクラスはデストラクター内のポインターを解放する責任があります。ポインタが別のクラスによって使用される可能性があるため、最初のクラスを破壊すると、第二を破っだろうが...

これら2人の取調べは似ています。それを作成したエンティティ以外のエンティティに知られているポインタを管理するにはどうすればよいですか?

注:私は、スマートポインタは、この問題を解決することができることを認識してんだけど、私は人々がそれらなしで行う方法を思ったんだけど。かなり問題になります

+4

'注:私はスマートポインタがこの問題を解決できると知っていますが、私は人々がそれらなしでどうしているのか疑問に思っています。 :) – etarion

+2

あなたが持っているものが有害だと思われるので、別の本を購入したいかもしれません:http://accu.org/index.php?module=bookreviews&func=search&rid=1744 – sellibitze

+0

@sellibitze – subb

答えて

1

。このポインタを解放するのは誰ですか? は現在 ですか?

私はペアの機能を示唆しています。

Xyz* CreateXyz(); 
void DestroyXyz(Xyz *xyz); 


Abc* NewAbc(); 
void DeleteAbc(Abc *abc); 

それとも、単にクライアント、すなわちもそれを使用した後、返されたオブジェクトに削除しなければならない関数を呼び出すものにXyz/Abcを削除するresponsibiltyを転送することができます。

作成したオブジェクトをどのように破壊するかをドキュメントで明確にしてください。

特に、削除する前に考慮すべきことがたくさんある場合は、ペア機能が好きです。

EDIT:あなたはDLLまたはいくつかの動的ライブラリを構築するとき、私は、このペア機能アプローチを示唆しています。実際には、これはオブジェクトが作成されたメモリプールのと同じメモリプールから破棄されます。誰もありません

+0

RAIIを使用するだけで何が問題になっていますか? – jalf

+0

DestroyXyz(xyz)の呼び出し方法削除xyzと異なる;問題は同じです。 "誰がDestroyXyz()を呼び出しますか" – Tonttu

+1

IMOこれはスマートポインタよりも優れていません。なぜなら、対応する 'DestroyXyz'または' DeleteAbc'呼び出しを忘れる可能性があるからです。 – AshleysBrain

0

は、

who is responsible for creating/destroying.あなたはロジックを定義します。

128バイトの長い文字列を格納するために512バイトのポインタを割り当てた場合は、文字列を正常に変更してファイルに保存した後、いつでもポインタを破棄できます。

2

オブジェクトの「所有権」とライフタイムは、C++の設計に大きな影響を与えます。一般的には、スマートポインタおよび類似の技術が好ましい。

しかし、スマートポインタなどを使用したくない場合は、非常に厳格でなければなりません。一般に、特定のオブジェクトのメモリ管理は、1つのインタフェースで発生する必要があります。そのため、ヒープベースのオブジェクト(createSomeObject()など)を作成する関数であれば、そのオブジェクトを削除する関数(たとえばdeleteSomeObject(SomeObject *))が必要です。もちろん、この種のガイドラインには常に例外があります。

これは良い文書で、誰かが戸惑い、メモリリークを引き起こす可能性を最小限に抑えます。

0

C++では「ポインタを作成するオブジェクト/関数がそれを解放する責任がある」とは必ずしも言えません。クラスファクトリでは、通常、オブジェクトを使用するコードは、ポインタの追加ユーザがないことを保証できる場合は、を削除します。それ以外の場合は、スマートポインタまたはリファレンスカウント用のScemeが必要です。

0

通常、ファクトリ関数は作成したオブジェクトを削除する責任を負いません。 1つのクラスに新規/削除のガイドラインを適用すると、特にマルチスレッド環境では ポインタをまったく返すことは事実上不可能になります。

ほとんどの場合、ドキュメント/参照は、明らかでないオブジェクトを削除する担当者を明示的に指定します。これを手動で処理しないで可能な解決策は私が思うガベージコレクションの分野に入るでしょう(参照カウンターは一般的なアプローチです)。

0

すべての状況で機能する簡単な答えはありません。ルールには常に例外があります。あなたは、あなたのソフトウェアに異なるアーキテクチャを考慮して、コードを読んでいる人に理解しやすいものがどれかを判断するだけです。

3

"誰が削除を担当しますか?"非常に良い質問です。そのような関数では、返されたポインタを削除しなければならないことを単に伝えるだけです。ファクトリのユーザは、どのクラスまたは関数が責任を持っているかを判断する必要があります。しかし、これは少し曖昧であり、確かに問題です。

最新のC++スタイルでは、これがスマートポインタが使用されている理由です。考えてみましょう:

std::unique_ptr<SomeObject> createSomeObject() { 
    return new SomeObject; 
} 

をこの場合、ポインタが返さunique_ptrが所有しています。どこに置いても、格納されたポインタはデストラクタで削除されます(スコープを外したとき、またはそれを含むオブジェクトが破壊するとき)。これにより、コードのどの部分が破壊され、削除が自動的に行われるのかが明らかになります(削除するか、または「破棄」することを忘れることはできません)。

2

これまで様々なアプローチがあります。

は、一つは、「ヒープに割り当てられていないされています。あなたの代わりにこれを行う場合は

SomeObject createSomeObject(){ 
    return SomeObject(); 
} 

は、誰もオブジェクトを解放しなければならない、とあなたが持っていますA 潜在的な欠点は、SomeObjectはコピー可能でなければならないが、多くの場合これは良い解決策であり、通常はデフォルトであるべきである。ユーザコードにnew/deleteを使用せず、コンストラクタ/デストラクタ呼び出し(例えば、おそらくSomeObjectはヒープ上にいくつかのデータを内部的に割り当て、オブジェクト自体が破壊されたときに解放します。

第二のアプローチは関連しているが、スマートポインタを使用しています。

std::shared_ptr<SomeObject> createSomeObject(){ 
    return std::make_shared(new SomeObject()); 
} 

これはあなたが必要とするものを削除する責任があるオブジェクトを返している、ポインタを返すていないという点で似ています削除されます。スマートポインタは、SomeObjectインスタンスの所有権を取得しており、適切な場合に削除します。

場合によっては、std::auto_ptrまたはstd::unique_ptrが好ましい場合があります。

いずれの場合でも、すべてのC++プログラマが知っておくべき非常に強力なイディオムであるRAIIに頼っています。リソースは常には、適切にコピーされ、移動され、内部リソースをクリーンアップするローカル(ヒープ割り当てされていない)オブジェクトでラップする必要があります。

0

裸の新しい&の削除がある場合、C++で例外セーフコードを書くことは基本的に不可能です。割り当てられたリソースをラップする

  • スマートポインタ:

    だから、あなたは基本的に2つの選択肢があります。

  • 参照カウントラッパークラスイディオムの周りにクラスを設計することで、裸の新しい&の削除を避けることができます。実際、これは本当に難しい方法で行われたスマートポインタの別名です。

基本的な考え方は、安価にコピーできるクラスのセットを作成し、参照カウントとコピーするのに費用がかかるリソースを保持する別のクラスをまとめたものです。

安価なコピークラスに代入演算子とコピー演算子を提供することで、intのような生の型と同じセマンティクスで渡すことができるデータ構造を得ることができます。

これはスマートポインタの再発明ではありませんが、シンタックスは非typedefのスマートポインタをコードで使用するよりも煩雑ではなく、C++コンストラクタについて十分に知っていれば十分ですラッパーを記述するための演算子のオーバーロードが含まれます。

0

Jalfはすでに重要なビットについて言及しています。つまり、必ずしもヒープに割り当てる必要はありません。

何か他のものは、これに果たし、かつ本はおそらくこれを教えてくれません。

C++は、OOPで特に良好ではありません。もともとOOPの目標を意味するクラスを持つC言語として設計されていたにもかかわらず、OOPは実際にはC++では非常に扱いにくく、ほとんどの現代のC++イディオムには焦点が当てられていません。

あなたは、あなたは基本的に2つの選択肢がありOPPの枠組みに縛られている場合:

  • スマートポインタ、または
  • ガベージコレクタ(私は最も広い意味で、このことを意味 - カスタム(例えばプール)アロケータもここで数えることができます)。

通常、C++で明示的なポインタとフリーストア管理を行わないとします。つまり、ビジネスオブジェクトをスタックに割り当て、すべての動的メモリ管理をRAII経由でカプセル化します。

もちろん、これにより、サブタイプ多型を達成することが非常に困難になります。しかしこれを軽減するために、C++は非常に抽象的な高水準のコード(おそらくOOPよりも)を書くことができる非常に強力なテンプレートメカニズムを提供しています。これは、オブジェクト指向からオフセットするために、アルゴリズム指向と呼ばれることもあります。 C++ <algorithms>ヘッダーと標準ライブラリコンテナは、これの良い例です。

関連する問題