要件
RCObject
「参照カウントオブジェクト」を表す、というクラスを作成しています。- クラス
RCObject
は抽象であり、フレームワークの基本クラスとして機能する必要があります(EC ++ 3アイテム7)。 RCObject
スタック上にサブクラスのインスタンスを作成することは禁止する必要があります( MEC ++ 1アイテム27)。[追加: ]
[仮定
Bear
はの具体的なサブクラスですRCObject
][
C.E.
ここでコンパイルエラーを意味します]Bear b1; // Triggers C.E. (by using MEC++1 Item 27) Bear* b2; // Not allowed but no way to trigger C.E. intrusive_ptr<Bear> b3; // Recommended Bear* bs1 = new Bear[8]; // Triggers C.E. container< intrusive_ptr<RCObject> > bs2; // Recommended intrusive_ptr_container<RCObject> bs3; // Recommended class SomeClass { private: Bear m_b1; // Triggers C.E. Bear* m_b2; // Not allowed but no way to trigger C.E. intrusive_ptr<Bear> m_b3; // Recommended };
明確化:生のポインタ
RCObject
(およびサブクラス)を宣言/返すことは禁止する必要があります(残念ながら、それを強制する実用的な方法はないと思います。つまり、ユーザーが従わない場合にコンパイルエラーをトリガーします)。上記の項目3のソースコードの例を参照してください。- サブクラスのインスタンスは、Java
RCObject
の場合と同じようCloneable
にクローン可能である必要があります。(MEC ++ 1アイテム25); サブクラス化するユーザーは、サブクラスの「ファクトリメソッド」
RCObject
を記述できる必要があります。戻り値が無視された(変数に割り当てられていない)場合でも、メモリリークは発生しないはずです。これに近いメカニズムはObjective-Cにあります。autorelease
[追加: cschwanとKos
RCObject
は、「smart-pointer-to- 」を返すだけで要件を満たすことができると指摘しました。]明確化:サブクラスのインスタンスは、適切なコンテナーまたはコンテナー
RCObject
に含めることができる必要があります。私は主に「-like」コンテナ、「-like 」コンテナ、「-like」コンテナが必要です。ベースラインはstd::
boost::
std::vector
std::set
std::map
intrusive_ptr<RCObject> my_bear = v[10];
と
m["John"] = my_bear;
期待どおりに動作します。
- ソースコードは、C++11のサポートが制限されたC++98コンパイラ(正確には、Visual Studio2008およびgcc4.6)を使用してコンパイルできる必要があります。
詳しくは
- 私はBoostの初心者です( Boostは非常に大きいので、それに慣れるのに少し時間が必要です。既存のすぐに使えるソリューションがあるかもしれませんが、そのようなソリューションに気付いていない可能性が高いです。 );
intrusive_ptr
パフォーマンスを考慮して、の代わりに使用したいと思いshared_ptr
ますが、両方と他の提案を受け入れることができます。make_shared()
、、()が役立つかどうかはわかりません(ちなみに、allocate_shared()
()はBoostではあまり宣伝されていないようです-スマートポインタのメインページでも見つかりませんでした)。enable_shared_from_this
enable_shared_from_this
- 「カスタムアロケータを書く」と聞いたことがありますが、複雑すぎるのではないかと思います。
- 個人的
RCObject
に継承すべきかどうか疑問に思います。boost::noncopyable
- すべての要件を満たす既存の実装が見つかりませんでした。
- フレームワークはゲームエンジンです。
- 主なターゲットプラットフォームはAndroidとiOSです。
- 引数依存のルックアップ(別名ケーニッヒルックアップ)を使用してそれらを実装する方法を知っ
intrusive_ptr_add_ref()
ています。intrusive_ptr_release()
- での使い方を知ってい
boost::atomic_size_t
ますboost:intrusive_ptr
。
クラス定義
namespace zoo {
class RCObject { ... }; // Abstract
class Animal : public RCObject { ... }; // Abstract
class Bear : public Animal { ... }; // Concrete
class Panda : public Bear { ... }; // Concrete
}
「非スマート」バージョン-createAnimal()[ファクトリメソッド]
zoo::Animal* createAnimal(bool isFacingExtinction, bool isBlackAndWhite) {
// I wish I could call result->autorelease() at the end...
zoo::Animal* result;
if (isFacingExtinction) {
if (isBlackAndWhite) {
result = new Panda;
} else {
result = new Bear;
}
} else {
result = 0;
}
return result;
}
「非スマート」バージョン-main()
int main() {
// Part 1 - Construction
zoo::RCObject* object1 = new zoo::Bear;
zoo::RCObject* object2 = new zoo::Panda;
zoo::Animal* animal1 = new zoo::Bear;
zoo::Animal* animal2 = new zoo::Panda;
zoo::Bear* bear1 = new zoo::Bear;
zoo::Bear* bear2 = new zoo::Panda;
//zoo::Panda* panda1 = new zoo::Bear; // Should fail
zoo::Panda* panda2 = new zoo::Panda;
// Creating instances of RCObject on the stack should fail by following
// the method described in the book MEC++1 Item 27.
//
//zoo::Bear b; // Should fail
//zoo::Panda p; // Should fail
// Part 2 - Object Assignment
*object1 = *animal1;
*object1 = *bear1;
*object1 = *bear2;
//*bear1 = *animal1; // Should fail
// Part 3 - Cloning
object1 = object2->clone();
object1 = animal1->clone();
object1 = animal2->clone();
//bear1 = animal1->clone(); // Should fail
return 0;
}
「スマート」バージョン[未完成!]
/* TODO: How to write the Factory Method? What should be returned? */
#include <boost/intrusive_ptr.hpp>
int main() {
// Part 1 - Construction
boost::intrusive_ptr<zoo::RCObject> object1(new zoo::Bear);
boost::intrusive_ptr<zoo::RCObject> object2(new zoo::Panda);
/* ... Skip (similar statements) ... */
//boost::intrusive_ptr<zoo::Panda> panda1(new zoo::Bear); // Should fail
boost::intrusive_ptr<zoo::Panda> panda2(new zoo::Panda);
// Creating instances of RCObject on the stack should fail by following
// the method described in the book MEC++1 Item 27. Unfortunately, there
// doesn't exist a way to ban the user from declaring a raw pointer to
// RCObject (and subclasses), all it relies is self discipline...
//
//zoo::Bear b; // Should fail
//zoo::Panda p; // Should fail
//zoo::Bear* pb; // No way to ban this
//zoo::Panda* pp; // No way to ban this
// Part 2 - Object Assignment
/* ... Skip (exactly the same as "non-smart") ... */
// Part 3 - Cloning
/* TODO: How to write this? */
return 0;
}
上記のコード(「スマートバージョン」)は、予想される使用パターンを示しています。この使用パターンがスマートポインターを使用するベストプラクティスに従っているかどうかはわかりません。そうでない場合は訂正してください。
同様の質問
shared_ptrをdeleteを使用しないようにします(受け入れられた答えはエレガントに見えます!!!それはある種の「カスタムデロケーター」ですか?
intrusive_ptr
時間とスペースの効率の点でどのように比較されるかわかりません)c ++ 11のintrusive_ptr(受け入れられた答えは言及され
make_shared()
、enable_shared_from_this
()ですが、「しかし、それでは、異なるスマートポインター型を使用して型を管理することはできません」の部分を理解していません)制御対象オブジェクト内に参照カウントを格納することにより、shared_ptrの効率を高める方法はありますか?(まだ消化中)
intrusive_ptr:なぜ共通ベースクラスが提供されないのですか?(答えは十分に詳細ではありません)
これはintrusive_ptrの有効な使用法ですか?(私はそれから何かを学びましたが、この質問の焦点は「スマートポインターを受け入れる関数に生のポインターを渡すこと」でした)
一般的な侵入型ポインタクライアントを使用した参照カウント(これは「CRTP」を使用しましたが、さらにサブクラス化すると頭痛がするのではないかと思います。単独
zoo::Panda
から拡張する必要がありますか、それとも両方を拡張する必要がありますか?)zoo::Bear
zoo::Bear
intrusive_base<zoo::Panda>
Boost shared_ptrを使用した埋め込み参照カウント(受け入れられた回答では、問題
std::enable_shared_from_this()
はないはずですが、boost::enable_shared_from_this()
いくつかの問題があるようです)
参考文献
- [ EC ++ 3 ]:効果的なC ++:プログラムとデザインを改善する55の特定の方法(第3版)Scott Meyers
- 項目7:ポリモーフィック基本クラスで仮想デストラクタを宣言する
- [ MEC ++ 1 ]:より効果的なC ++:プログラムとデザインを改善する35の新しい方法(第1版)Scott Meyers
- 項目25:コンストラクターと非メンバー関数の仮想化
- 項目27:ヒープベースのオブジェクトの要求または禁止。