web-dev-qa-db-ja.com

C ++ STLのようなベクタークラスを探していますが、スタックストレージを使用しています

自分で書く前に、みんなに質問します。

私は、STLベクトルとほとんど同じですが、スタック上の配列にデータを格納するC++クラスを探しています。ある種のSTLアロケータークラスも機能しますが、静的に割り当てられたスレッドごとのヒープでさえ、どんな種類のヒープも回避しようとしています(そのうちの1つは2番目の選択肢です)。スタックの方が効率的です。

これは、ベクトルを使用する現在のコードの代わりに使用する必要があります。

私がこれから書こうとしていることについて、私はこのようなことを考えていました:

char buffer[4096];
stack_vector<match_item> matches(buffer, sizeof(buffer));

または、クラスにバッファスペースを内部的に割り当てることもできます。その後、次のようになります。

stack_vector<match_item, 256> matches;

スペースが足りなくなった場合にstd :: bad_allocがスローされると思っていましたが、これは発生しません。

更新

Chromiumのstack_container.hを使用するとうまくいきます!

私がこの方法でこれを行うことを考えていなかった理由は、STLコレクションコンストラクターのアロケーターオブジェクトパラメーターを常に見落としているためです。静的プールを実行するためにテンプレートパラメータを数回使用しましたが、実際にオブジェクトパラメータを使用するコードを見たり、記述したりしたことはありません。新しいことを学びました。とてもかっこいい!

コードは少し面倒で、何らかの理由でGCCは、アロケーターをベクターのアロケーターパラメーターに構築するのではなく、実際のアイテムとして宣言するように強制しました。それはこのようなものから行きました:

typedef std::pair< const char *, const char * > comp_list_item;
typedef std::vector< comp_list_item > comp_list_type;

comp_list_type match_list;
match_list.reserve(32);

これに:

static const size_t comp_list_alloc_size = 128;
typedef std::pair< const char *, const char * > comp_list_item;
typedef StackAllocator< comp_list_item, comp_list_alloc_size > comp_list_alloc_type;
typedef std::vector< comp_list_item, comp_list_alloc_type > comp_list_type;

comp_list_alloc_type::Source match_list_buffer;
comp_list_alloc_type match_list_alloc( &match_list_buffer );
comp_list_type match_list( match_list_alloc );
match_list.reserve( comp_list_alloc_size );

そして、私は新しいものを宣言するときはいつでもそれを繰り返さなければなりません。しかし、それは私が望んでいたように機能します。

Stack_container.hにStackVectorが定義されていることに気づき、それを使ってみました。ただし、ベクターから継承したり、同じメソッドを定義したりしないため、ドロップインの置き換えではありませんでした。ベクターを使用してすべてのコードを書き直したくなかったので、あきらめました。

51
Zan Lynx

完全に新しいコンテナクラスを記述する必要はありません。 STLコンテナーを使用できますが、たとえば_std::vector_の2番目のパラメーターを変更して、スタックバッファーから割り当てるカスタムアロケーターを割り当てます。 chromiumの作者は、このためのアロケータを作成しました。

https://chromium.googlesource.com/chromium/chromium/+/master/base/stack_container.h

それはあなたがそれがどれくらい大きいかを言うところにバッファを割り当てることによって機能します。コンテナーを作成し、container.reserve(buffer_size);を呼び出します。そのサイズをオーバーフローすると、アロケーターはヒープから要素を自動的に取得します(これは_std::allocator_から派生するため、その場合は標準アロケーターの機能を使用します)。まだ試したことはありませんが、グーグルのもののようですので、試してみる価値はあると思います。

使い方は次のとおりです:

_StackVector<int, 128> s;
s->Push_back(42); // overloaded operator->
s->Push_back(43);

// to get the real std::vector. 
StackVector<int, 128>::ContainerType & v = s.container();
std::cout << v[0] << " " << v[1] << std::endl;
_

boost :: static_vector が検索対象のようです。ドキュメントから:

static_vectorは、ベクターと配列のハイブリッドです。ベクターと同様に、これは、静的割り当て、低オーバーヘッド、および配列の固定容量とともに、サイズが変化する可能性がある連続したストレージを持つシーケンスコンテナーです。 static_vectorは、Adam WulkiewiczとAndrew Hundtの高性能varrayクラスに基づいています。

要素は配列と同様にオブジェクト自体に格納されるため、static_vectorの要素数は固定容量まで動的に変化する可能性があります。

16
Yury

あなたが見たいと思うかもしれないいくつかのオプション:

Matthew Wilson(Imperfect C++の作者)によるSTLSoftには、デフォルトの配列をスタックに配置する_auto_buffer_テンプレートクラスがありますが、それがスタックより大きくなると、ヒープからメモリを取得します。私はこのクラスが好きです-コンテナーのサイズが一般にかなり低い制限によって制限されることがわかっている場合は、ローカルでスタックに割り当てられた配列の速度が得られます。ただし、より多くのメモリを必要とするコーナーケースでは、すべて正しく機能します。

http://www.stlsoft.org/doc-1.9/classstlsoft_1_1auto__buffer.html

私が使用している実装はSTLSoftの実装ではなく、そこから大きく借りている実装であることに注意してください。

「レイジープログラマー」は、ストレージにalloca()を使用するコンテナーの実装について投稿しました。私はこのテクニックのファンではありませんが、それがあなたが望むものであるかどうか、あなたにあなた自身で決定させます:

http://tlzprgmr.wordpress.com/2008/04/02/c-how-to-create-variable-length-arrays-on-the-stack/

次に、最初の2つの動的なサイズ変更動作がない_boost::array_がありますが、組み込み配列で取得する反復子としてポインタを使用するだけよりも多くのvectorインターフェイスを提供します(つまり、 、begin()end()size()などを取得します):

http://www.boost.org/doc/libs/1_37_0/doc/html/boost/array.html

11
Michael Burr

独自のアロケータをstd :: vectorに使用して、例のようにスタックベースのストレージのチャンクを割り当てることができます。アロケータクラスは、テンプレートの2番目の部分です。

編集:私はこれを試したことがないので、ドキュメントを見ると、独自のアロケータを作成できないとさらに確信します。まだ調査中です。

4
Mark Ransom

速度が重要な場合は、実行時間を確認します

  • 4 ns int [10]、スタック上の固定サイズ
  • 40 ns <vector>
  • 1300 ns <stlsoft/containers/pod_vector.hpp>

以下の1つの愚かなテスト-2つのプッシュ、v [0] v [1]、2つのポップ、1つのプラットフォーム、mac ppc、gcc-4.2 -O3のみ。 (Appleがstlを最適化したかどうかはわかりません。)

自分で偽ったことのないタイミングを受け入れないでください。そしてもちろん、すべての使用パターンは異なります。それにもかかわらず、2つ以上の要因が私を驚かせます。

(メモリ、メモリアクセスがランタイムでの主な要因である場合、さまざまな実装で余分なメモリはすべて何ですか?)

#include <stlsoft/containers/pod_vector.hpp>
#include <stdio.h>
using namespace std;

int main( int argc, char* argv[] )
{
        // times for 2 Push, v[0] v[1], 2 pop, mac g4 ppc gcc-4.2 -O3 --
    // Vecint10 v;  // stack int[10]: 4 ns
    vector<int> v;  // 40 ns
    // stlsoft::pod_vector<int> v;  // 1300 ns
    // stlsoft::pod_vector<int, std::allocator<int>, 64> v;

    int n = (argv[1] ? atoi( argv[1] ) : 10) * 1000000;
    int sum = 0;

    while( --n >= 0 ){
        v.Push_back( n );
        v.Push_back( n );
        sum += v[0] + v[1];
        v.pop_back();
        v.pop_back();
    }
    printf( "sum: %d\n", sum );

}
4
denis

tr1 :: arrayは、説明と部分的に一致します。 Push ___ back()などの機能はありませんが、出発点として検討する価値があるかもしれません。それをラップして、 "back"にインデックスを追加してPush_back()などをサポートするのは、かなり簡単なはずです。

3
Boojum

特にstackに配置する理由は何ですか? alloca()の実装がある場合、malloc()の代わりにそれを使用してクラスアロケーターを作成できますが、静的に割り当てられた配列を使用するという考えはさらに優れています。ほとんどのアーキテクチャで同じくらい高速であり、あなたのスタックの破損を台無しにする危険があります。

2
Charlie Martin

Qtを使用している可能性があります。次に、QVarLengthArraydocs )を使用することをお勧めします。それは基本的にstd::vectorstd::arrayの間にあり、一定の量を静的に割り当て、必要に応じてヒープ割り当てにフォールバックします。

私がそれを使っていたなら、私はブースト版を好むでしょう。

2
Sebastian Graf

ブーストはこれを持っています。その呼び出された small_vector

small_vectorは、要素が少ない場合に最適化されたベクターのようなコンテナーです。事前に割り当てられたいくつかの要素がインプレースで含まれているため、要素の実際の数が事前に割り当てられたしきい値を下回っている場合に、動的ストレージ割り当ての使用を回避できます。 small_vectorは、LLVMのSmallVectorコンテナーに触発されました。 static_vectorとは異なり、small_vectorの容量は、事前に割り当てられた初期容量を超える可能性があります。

small_vectorはsmall_vector_baseに変換できます。これは、事前割り当てされた要素の数から独立したタイプであり、そのN引数でテンプレート化する必要のないクライアントコードを許可します。 small_vectorはすべてのベクターのメンバー関数を継承するため、配置、ステートフルアロケーターなどのすべての標準機能をサポートします。

1
fandyushin

スタックに割り当てたいが、コンパイル時に最大サイズを事前に定義したくない場合は、次のように使用できる小さな実装である StackVector を使用できます。

_new_stack_vector(Type, name, size)
_

ここで、Typeはベクター内の要素のタイプ、nameはベクターの変数名、sizeはベクター内で許容される要素の最大数です。

sizeは変数にすることができ、コンパイル時の定数である必要はありません。 :D

例:

_new_stack_vector(int, vec, 100); //like vector<int> vec; vec.reserve(100); but on the stack :)
vec.Push_back(10); //added "10" as the first item in the vector
_

...そしてそれだけです!

免責事項:一般に、スタックでは非常に大きな配列サイズを使用しないでください。 _int var[9999999]_を使用してはならないように、new_stack_vector(int, vec, 9999999)も同様に使用しないでください。責任を持って使用してください。

0
MathuSum Mut