2012-03-16 6 views
0

任意のPODを保持できるベクターがありますか?任意のPODを保持できるベクター

anyvector v; 
v.push_back<int>(1); 
v.push_back<somestruct>({1, 2, 3}); 

としてアクセスして:ような何か

int a = v.get<int>(0); 
somestruct b = v.get<somestruct>(1); 

私はそこに、各要素のオフセットを保存するためのオーバーヘッドでなければならないが、それは私ですvector<boost::any>のオーバーヘッド未満でなければなら知っています現在のソリューション。
私が必要とする操作は、挿入終了、終了からの削除、ランダムアクセスです。
私はそれを実装するための問題ではなく、準備ができているかどうかを尋ねるだけです。

編集:ポインターを使用してデータを格納するソリューション(boost::anyboost::variant)は、私が探している線形ストレージを使用することに比べて大きなオーバーヘッドです。

+4

ブーストの[Any](http://www.boost.org/doc/libs/1_49_0/doc/html/any.html)と[Variant](http://www.boost.org /doc/libs/1_49_0/doc/html/variant.html) – megabyte1024

+0

@ megabyte1024:私が言ったように、私の現在の解決策ですが、それぞれが線形ストレージに対する大きなオーバーヘッドであるポインタを持っています。 – Dani

+0

Qtを使用している場合はQVariantを使用してください。 Any-Type-Variableを最初に作成すること(Any、Variant、QVariant)に集中して、これをベクトルに入れることは、単にその型のstd :: vectorを使うことです。 – Patrick

答えて

3
std::vector<boost::variant<int,somestruct,...>> v; 

v.push_back(1); 
v.push_back(({1, 2, 3}); 

a = boost::get<int>(v[0]); 

宣言時にどの型を処理する必要があるのか​​をご存じの場合は、

- ジェームズ・観世オフセットのベクトルを維持することがboost::anyに非常に似ていると私はあなたが本当に、よりコンパクトにすることができるかわからない、言ったようにJohannesDがboost::variant影響各要素の大きさが、 を言ったように

を編集。

厳密な要件に応じて、別の解決方法が役立ちます。 各タイプごとに異なるコンテナを内部的に格納しますが、複数のベクトルを直接使用するよりもはるかに優れているわけではありませんが、格納されている最後のいくつかの要素のような余分な情報を格納できます。あなたはまだ一箇所にすべてのものを持っています。以下のよう
何か:あなたがマップによってベクトルを交換するため、要素IDを覚えることができる。もちろん、

template <template <class,class> class C, typename T, typename ...Args> 
struct map_ { //FIXME: return a list of type C<T1>,C<T2>... 
}; 

template <template <class...> class C, typename ...Args> 
struct fill_ { // Hack to parametrize map by Args on GCC 4.6 
typedef T<Args> type; 
}; 

template <typename... Ts> 
struct hvec 
{ 
std::map<std::string,fill_<boost::variant,map_<std::vector,Ts>> vec_map; 
std::size_t last_id; 
std::string last_typeid; 

template <typename T> 
T get(std::size_t i) 
{ 
    std::vector<T>& v = vec_map[typeid(T).name]; 
    return vec[i]; 
} 

template <typename T> 
std::size_t push_back(const T& e) 
{ 
    std::vector<T>& v = vec_map[typeid(T).name]; 
    v.push_back(e); 
} 
}; 

、これはあなたの要件を満たすが、余分なコストを追加し、まだ一つの要素によって「アドレス」/キーを意味します。ただし、この場合、指定されたオフセットで要素の型を覚える必要はありません。

+0

私が言ったように、それは私の現在のソリューション(boost:any)ですが、それぞれが線形ストレージに対する大きなオーバーヘッドであるポインタを持っています。 – Dani

+0

@Daniスティーブの答えを見れば、このオーバーヘッドが発生します。私は、 'boost :: any'や' boost :: variant'よりも、別の解決策が根本的に効率的であるとは思いません。 –

+0

@Konrad:私の答えは間違っていました。実際に必要とされる操作に焦点を当てる必要があるときに、「一種のベクトル」に焦点を当てました。ランダムアクセスでオーバーヘッドが発生しますが、2つの選択肢があります。あなたはベクトルの外にデータを割り当てることができ、固定サイズのポインタ(boost :: anyのような)を持たせることもできますし、要素を大規模な配列に配置し、別々の配列マッピングインデックスを保持してデータ。後者は、通常のメモリアロケータが想定することができない最後にのみ削除が行われるという事実に依存して、別々の割り当てよりもオーバーヘッドが少ない可能性があります。 –

0

あなたはポインタを必要としません。つまり、PODを直接格納できる大きさの要素型が必要です。 PODオブジェクトが任意のサイズを持つことができれば、これは明らかに不可能です。

候補タイプのセットがある場合は、サイズの制限された結合を持つことができるようですが、Boost.Variantはそうではありません。ドキュメントは、可能であればスタックベース(おそらくはインライン)になることを示しています。この "大きな間接費"をどのように測定しましたか?

+0

私は結合体が欲しくない、私は任意のサイズの要素を含むことができるベクトルが欲しい – Dani

+0

要素のサイズが固定されていない場合、このコンテナは、ベクトルや配列のような、意味のある意味では機能しません。インデックスのオフセットを計算する方法は? – Useless

+0

彼はO(n)検索時間を望んでいると思う。または、オフセットを格納する余分なメモリをO(n)にすることもできます。 – bames53

0

あなたは参照によってまたは値によってオブジェクトを格納するために、あなたの選択であるベクトルの組み合わせのようなsoemthingを試してみて、

enum ElementType : unsigned int 
{ 
    ET_INT, 
    ET_WHATEVER 
}; 

vector < pair < void*, unsigned int >* > v; 
pair < void*, unsigned int > prv; 
int i; 

prv.first = &i; 
prv.second = ET_INT; 

v.push_back(&prv); 

をペアリングできます。 singloe要素へのアクセスは、そのようになります:

int a = *(int*) v.at(0)->first 

はそれがすべての保存された要素のタイプにあなたに固定ベクタ要素のサイズと情報を与えるだろう。参照によってオブジェクトを保存するときに生存時間と名前空間を注意する必要がありますが、タイプからの変換を優先し、ヒューサイズのパラメータを毎回関数に渡すのではなく、voidポインタが有効であることを確認します。

はそれが役に立てば幸い;)

3

私は1つのことを聞いたことがない、もう1つは、それがどのように 非常に特別な与えられ、存在する場合、私は驚かれることと思います。ただし、 の2つのベクトルを使用することは難しくありません。つまり、オブジェクトを置く生のメモリ の場合はstd::vector<unsigned char>、インデックスをマップする場合はstd::vector<size_t>です。 PODのみが含まれている限り、memcpyを使用して 要素を挿入できます。アライメントを尊重することを忘れないでください。そして、インデックス は、インデックスをマップします。 は、後でpush_backによって無効にされるため、ポインタをポインタに入れないでください。

そのため、 を保持するものを実装するのは難しくありません.PODでない場合でも、配置の新規および明示的な破棄を使用します。 唯一の本当の問題はアラインメントです。 ベクターに挿入するときは、多型デストラクタ 型のインスタンスも保存する必要があります。これはちょっと難しいかもしれませんが、少なくとも の練習では、実行可能です。基本的には、boost::anyの内容を複製していますが、動的メモリへのポインタの代わりに を複製すると、2番目の配列の "動的メモリ" が得られます。

+0

私が期待している主な問題は、destructirsを呼び出す必要があることです。これは、PODの場合でもそうでない場合もあります。作成されるオブジェクトは、PODのためにはしばしば行われませんが、破壊する必要があります。この権利が得られたら、 'std :: vector 'を効果的に実装したと思います。 –

+1

@DietmarKühl** IF **オブジェクトには些細なデストラクタ(IMHOの場合は大きい)があることを保証できます。次に、デストラクタをスキップできます。より多くの点: 'vector'によって使用されるアロケータは問題ではありません。あなたが実装しているのは、あなたのアロケータを使用する 'boost :: any'に相当します:基本的に' any'のベクトルを持ちます。 'any'はメモリのソースとして' unsigned char'のベクトルを使います、標準の「新しい」よりむしろ。 (もちろん、ベクトルが成長したときの無効化を避けるために、 "ポインタ"を 'size_t'として維持しなければならないでしょう)。 –

0

std :: tupleは任意のサイズの要素のシーケンスを格納できますが、固定セットのみを格納できます。

実行時に任意の型の任意の数の要素がエラーを発生しやすく、非常に危険です。あなたが次のことをすれば、何が起こると思いますか?

anyvector v; 
v.push_back<Foo>(Foo()); 
int i = v.back<int>(); 

実装は実行時例外をご提供できれば、あなたは幸運になるだろう、と私はanyvectorの実装がそれを保証することができることをどのような方法はないと思います。たとえば、RTTIを使用しようとすると、異なるタイプを参照する2つのtype_infoオブジェクトが等しくないという保証はないという問題が発生します。

0

私はあなたが望むものに最善の近似を得るために、あなた自身のデータ構造を構築する必要があると思います。次の2つの実装タイプのオフあなたのタイプをベースにすることができます

std::vector<unsigned char> blobStorage_; 
std::vector<size_t> offsetMap_; 

これは効果的ブロブにシリアライズアクセス個々のオブジェクトをオフセットする能力を持つ直列化ブロブの実装です。

オブジェクトを一backしたい、あなたは

  1. blobStorage
  2. の終わりにシリアライズそれはoffsetMap

へのオフセット(新しいオブジェクトのブロブのフロント)を追加します同様に、ベクトル[n]と考えるアクセス要素が必要な場合、あなたは

  1. からオフセットを取得します。 offsetMap_ [N]
  2. blobStorage_から供給されたタイプなどのオブジェクトdeserialiseこれらの動作の

両方を[オフセット]は順序O(はsizeof(オブジェクト))が、事実上一定です。

通常、このようなことをしたいときは、 "実際の"という意味では実際にプログラムにシリアライズを設計することを意味します。これは、通常、タイプIDと潜在的にサイズ情報を与えるタイプのストレージへの標準ヘッダーを使用することを意味します。あなたが通常これを行う理由は、シリアライズ時に型情報が失われ、指示した使用パターン(型がgetで提供されているところ)で書かれていない契約が多い非常に壊れやすいプログラムを構築しているからです。あなたは通常、他の人と仕事をする専門的な環境であなたのプログラムを簡単に中断させたくありません。したがって、型IDを格納し、その型IDで型をより大きな直列化設計の中に登録することで、より堅牢にすることができます。次に、「ベクトル」は、正しいタイプのオブジェクトを逆シリアル化して提示する方法を認識します。このようなアレイ内の連続配列

  • として

  • 0
    • std::vector記憶素子の各要素は、
    • PODタイプを持っている方法はありません
    • 任意に大きくすることができる前の要素過去開始アドレスsizeof(Elem)を有しますsizeof(Elem)は無制限なので、任意の大きなオブジェクトのベクトルです。

    答えは、あなた自身をさらに制限することができない限り、単にnoです。

    上限サイズを設定できる場合は、オーバーヘッドなしで可能です。 PODオブジェクトは明示的な構成なしで使用することも、明示的な破棄をせずに削除することもできます。したがって、希望のタイプの要素をstd::array< char, N >reinterpret_castのベクトルで作成することができます。

    typedef std::vector< std::array< char, pod_size_max > > pod_variant_vector; 
    
    template< typename destination > 
    destination &get(pod_variant_vector &vec, std::size_t index) 
        { return reinterpret_cast< destination & >(vec[ index ]); } 
    
    template< typename destination > 
    destination const &get(pod_variant_vector const &vec, std::size_t index) 
        { return reinterpret_cast< destination const & >(vec[ index ]); } 
    

    それはあなたがgetティンものと同じタイプを使用して初期化される前にそのようなオブジェクトの値を使用しないでください。

    関連する問題