8

boost::shared_array<T>(または) がある場合、配列と共有する をboost::shared_ptr<T[]>取得する方法はありますか?boost::shared_ptr<T>

たとえば、次のように書きたいと思うかもしれません。

shared_array<int> array(new int[10]);
shared_ptr<int> element = &array[2];

&array[2]は type しかないため、使用できないことはわかっています。その型を取る暗黙のコンストラクターを持つint *ことは危険です。shared_ptr<int>理想的shared_array<int>には、次のようなインスタンス メソッドが必要です。

shared_ptr<int> element = array.shared_ptr_to(2);

残念ながら、私はこのようなものを見つけることができません。shared_ptr<int>別の とエイリアスするエイリアスコンストラクターがありますが、;shared_ptr<T>とのエイリアスは許可されません。shared_array<T>だから私もこれを書くことはできません(コンパイルされません):

shared_ptr<int> element(array, &array[2]);
//Can't convert 'array' from shared_array<int> to shared_ptr<int>

私が試した別のオプションは、std::shared_ptr<T>(stdの代わりにboost) を使用することでした。の特化T[]は標準化されていないので、自分で定義しようと思いました。残念ながら、エイリアシング コンストラクターの内部構造を壊さない方法でそれが実際に可能だとは思いませんstd::shared_ptr<T[]>。これは、実装固有のスーパータイプに my をキャストしようとするためです。(私は現在、ブースト 1 から継承しているだけです。) このアイデアの良い点は、インスタンスshared_ptr_toメソッドを実装できることです。

これは私が実験した別のアイデアですが、大規模なプロジェクト全体で使用する可能性があるものとして受け入れられるほど効率的ではないと思います.

template<typename T>
boost::shared_ptr<T> GetElementPtr(const boost::shared_array<T> &array, size_t index) {
    //This deleter works by holding on to the underlying array until the deleter itself is deleted.
    struct {
        boost::shared_array<T> array;
        void operator()(T *) {} //No action required here.
    } deleter = { array };
    return shared_ptr<T>(&array[index], deleter);
}

次に試みるのは、Boost 1.53.0 (現在は 1.50.0 しかありません) にアップグレードするshared_ptr<T[]>ことです。これがうまくいくことを願っていますが、まだ試す機会がありませんでした:shared_array<T>booststd

shared_ptr<int[]> array(new int[10]);
shared_ptr<int> element(array, &array[2]);

もちろん、私はまだインスタンスメソッドの構文を好むでしょうが、私はそれでは運が悪いと思います (Boost の変更を除いて):

shared_ptr<int> element = array.shared_ptr_to(2);

他に何かアイデアはありますか?

4

3 に答える 3

1

あなたは奇妙なことをしています。なぜshared_ptr要素が必要なのですか?配列の要素を別の場所に渡して、配列を削除しないようにしますか?

はいの場合、よりもstd::vector<shared_ptr<T>>適しています。そのソリューションは安全で標準的であり、オブジェクトの削除がきめ細かく行われます

于 2013-03-21T14:06:06.833 に答える
0

boost::shared_ptrこれをネイティブにサポートしていないようです。たぶん、カスタムのデリータでこれを回避できます。ただしstd::shared_ptr 、必要なものをサポートする特別なコンストラクターを提供します。

struct foo
{
    int a;
    double b;
};

int main()
{
    auto sp1 = std::make_shared<foo>();
    std::shared_ptr<int> sp2 (sp1,&sp1->a);
}

ここでは、オブジェクトの所有権を共有していますがsp1sp2そのメンバーを指しています。が破棄された場合でも、オブジェクトは存続し、有効です。foosp2sp1foosp2

于 2013-03-21T14:23:35.200 に答える
0

これが私が最終的にやったことです。

の独自の実装を作成しshared_array<T>ました。ユーザーがベクトルを取得できないように、shared_ptr<vector<T>>実際に独自のラッパーを拡張することを除いて、効果的に拡張します。vector<T>これは、サイズが変更されないことを保証できることを意味します。次に、必要なインスタンス メソッドを実装しましweak_ptr_to(size_t)operator[]

私の実装ではstd::make_shared、ベクトルを作成するために使用します。そのため、ベクターは制御ブロックとは別に内部配列ストレージを割り当てますが、ベクター自体は制御ブロックのメンバーになります。したがってstd::make_shared、通常の型の使用を忘れることとほぼ同じですが、これらは配列であるため、大きくて少ない可能性が高いため、それほど重要ではありません.

に基づいた実装を作成することもできますshared_ptr<T>が、default_delete<T[]>必要なものは何でもありますが、制御ブロックとは別に配列を割り当てる必要があります (そのため、ベクトルに対してあまり節約できません)。動的にサイズ変更された配列を制御ブロックに埋め込む移植可能な方法はないと思います。

または、私の実装は に基づいておりboost::shared_array<T>、要素ポインタを取得するときにカスタム デリータを使用できます (質問の例のように)。ほとんどの場合、これはおそらくさらに悪いことです。これは、配列を割り当てる 1 回限りのヒットではなく、エイリアス化されたポインターを取得するたびにヒットが発生するためです (これは非常に短命のポインターで多く発生する可能性があります)。

さらに最適化するための唯一の合理的な方法は、最新のブーストを使用することだと思います(機能する場合。主に自分のインスタンスメンバーへの欲求のために、気が変わる前に試してみるまでには至りませんでした)。そしてもちろん、これはboost単一のオブジェクトであっても、あらゆる場所で使用することを意味します。

しかし、私が行った主な利点は、Visual Studio のデバッガーが std::shared_ptrs と std::vectors の内容を表示するのが得意であり (私が聞いたところ)、boost の内容を分析するのが (私たちが期待する) あまり得意ではないことです。ものやカスタムのもの。

だから私がやったことは基本的に最適だと思います。:)

于 2013-03-21T23:16:19.517 に答える