2009-05-18 6 views
13

オブジェクトのようにshared_ptrが必要ですが、メンバーにアクセスしようとすると自動的に実際のオブジェクトが作成されます。C++レイジーポインタはありますか?

例えば、私が持っている:

class Box 
{ 
public: 
    unsigned int width; 
    unsigned int height; 
    Box(): width(50), height(100){} 
}; 

std::vector< lazy<Box> > boxes; 
boxes.resize(100); 

// at this point boxes contain no any real Box object. 
// But when I try to access box number 50, for example, 
// it will be created. 

std::cout << boxes[49].width; 

// now vector contains one real box and 99 lazy boxes. 

は、いくつかの実装があり、または私は自分自身を書くことする必要がありますか?

答えて

17

自分のロールを張るのにはほとんど手間がかかりません。 boost::optionalを使用して

template<typename T> 
class lazy { 
public: 
    lazy() : child(0) {} 
    ~lazy() { delete child; } 
    T &operator*() { 
     if (!child) child = new T; 
     return *child; 
    } 
    // might dereference NULL pointer if unset... 
    // but if this is const, what else can be done? 
    const T &operator*() const { return *child; } 
    T *operator->() { return &**this; } 
    const T *operator->() const { return &**this; } 
private: 
    T *child; 
}; 

// ... 

cout << boxes[49]->width; 
+2

auto_ptrとして子を入れるのは意味をなさないでしょう –

+0

しかし、ボックス[49] - > widthを初期化して、初期化されていない値(0ではない)をどのようにしたらよいでしょうか?おそらく、*(boxes [49])のコンストラクタがそのインデックスを引数として受け取り、他のボックスと区別できるようにするためのインタフェースが必要です。つまり、std:vector以外のものを使うことを意味し、スパースベクトル/行列の領域に入れます。 –

+2

子ポインタの代わりにboost :: optionalのを使用することもできます。 boost :: optionalを使ってを使うと、スタック割り当ての利点が得られます。ヒープが使用されていません –

2

私はそのようなことについて聞いたことはありませんが、聞いたことのないことがたくさんあります。 「レイジーポインタ」は、基礎となるクラスのインスタンスに有用なデータをどのように入れますか?

本当にsparse matrixはあなたが本当に探しているものではありませんか?

+1

なぜあなたはスパース行列を指していましたか? –

+0

スパース行列は類似した(同じではありませんが)必要を満たすためです。ポスターの例では、「遅延ポインター」のベクトルが表示されています。これはまばらな行列のように聞こえる。 –

0

私の知る限りでは、この種の実装はありません。しかし、それを作成することは難しくありません。

10

、あなたはそのようなことを持つことができます。

// 100 lazy BigStuffs 
std::vector< boost::optional<BigStuff> > v(100); 
v[49] = some_big_stuff; 

は100怠惰なのを構築し、v[49]に1つの実some_big_stuffを割り当てます。 boost::optionalはヒープメモリを使用しませんが、スタック割り当てバッファにオブジェクトを作成するには、placement-newを使用します。私はこのようなboost::optionalの周りにラッパーを作成します。

template<typename T> 
struct LazyPtr { 
    T& operator*() { if(!opt) opt = T(); return *opt; } 
    T const& operator*() const { return *opt; } 

    T* operator->() { if(!opt) opt = T(); return &*opt; } 
    T const* operator->() const { return &*opt; }  
private: 
    boost::optional<T> opt; 
}; 

これが今のstuffsを行うためのboost::optionalを使用しています。

T& operator*() { if(!opt) opt = boost::in_place(); return *opt; } 

任意のコピー-INGを必要としない:それは(op*上の例)このようなインプレース構築をサポートするべきです。しかし、現在のブーストマニュアルには、その代入演算子のオーバーロードは含まれていません。しかし、ソースはします。私はこれが単なるマニュアルの欠陥であるのか、その文書が故意に除外されているのかどうかは分かりません。ですから、T()を使用してコピー割り当てを使用してより安全な方法を使用します。

+2

'ベクトル> v(100)'は100 * sizeof(Box)を使用しますが、これはおそらく大丈夫ですが、OPは割り当てられていないボックスにメモリを使いたくないかもしれません。 OPはより多くの要件を記述していないので、私達はわからない... – ephemient

+0

あなたは正しい、それは良い点だ:) –

+0

右、私は割り当てられていないオブジェクトのスペースを無駄にしたくない。 –

関連する問題