1

任意の数の動的に作成された (さまざまなタイプの) インスタンスを STL コンテナーに格納して、後でコンテナーのみを使用してメモリを解放できるようにするにはどうすればよいでしょうか?

次のように動作するはずです。

std::vector< void * > vec;
vec.push_back( new int(10) );
vec.push_back( new float(1.) );

現在、vecスコープ外になると、インスタンスへのポインターは破棄されますが、 と のメモリは解放されませんintfloatそして明らかに私はできません:

for( auto i : vec )
  delete *i;

void*オブジェクトへのポインタ型ではないためです。

ベクトルの要素にアクセスできないため、これは良い考えではないと反対し、主張することができます。そうです、私はそれらにアクセスしません。NVIDIA ドライバーはvoid*、カーネル呼び出しのパラメーターに必要なアドレス (問題ありません) だけであるため、それらにアクセスします。

ここでの問題は、さまざまなタイプが格納される可能性があることだと思います。これを引数としてcudaunionカーネルに渡したい場合に備えて、トリックを実行できるかどうか疑問に思っています。

カーネルはさまざまな型のパラメーターを受け取り、事前に型がわからない式ツリー (式テンプレート) を走査することによって収集されます。したがって、リーフにアクセスすると、パラメーターが保存されます。void* および組み込み型 int、float などのみを指定できます。

ベクトルは、カーネルの起動直後に削除できます (起動は非同期ですが、ドライバーは最初にパラメーターをコピーしてからホスト スレッドを続行します)。2 番目の質問: 各引数は void* としてドライバーに渡されます。int、float、または void* であるかどうかに関係なく。したがって、必要以上のメモリを割り当てることができると思います。組合のことは一見の価値があると思います。

4

5 に答える 5

5

サポートするタイプごとに1つのベクトルを使用できます。

しかし、それはのベクトルのアイデアの大きな改善ですがvoid*、それでもかなり臭いです。

これはXY問題のように聞こえます。問題Xがあり、解決策Yを想定していますが、Yは明らかに何らかの巧妙な適応なしでは機能しないので、Yについて質問してください。代わりに、実際の問題について質問する必要があります。 X.どちらですか?

于 2012-10-31T15:58:36.820 に答える
1

はい、FWIW

インプレースnewとを組み合わせて使用​​することをお勧めしmallocます。これが行うことはvoid*、ベクターのように作成されたポインターを格納できるようにすることです。次に、ベクトルが終了したら、単純に繰り返してfree()呼び出すことができます。

IE

void* ptr = malloc(sizeof(int));
int* myNiceInt = new (ptr) int(myNiceValue);
vec.push_back(ptr);

//at some point later iterate over vec
free( *iter );

この場合、これが問題の最も簡単な解決策になると思いますが、これは「C」のような答えであることを受け入れてください。

言ってるだけ' ;)

于 2012-10-31T16:38:59.480 に答える
0

「NVIDIA ドライバー」はとにかく C インターフェイスのように聞こえるのでmalloc、クレイジーな提案ではありません。

別の方法として、ユニオンを使用することをお勧めします...ただし、「タグ」を並列ベクトルに格納して、要素の実際の型を記録し、削除時に適切な型にキャストできるようにする必要もあります。

つまり、void *適切な型にキャストする前にキャストする必要がありdeleteます。「C++ の方法」は、仮想デストラクタを持つ基本クラスを持つことです。deleteサブクラスのインスタンスを指している場合は、それを呼び出すことができます。ただし、使用しているライブラリが既に型を決定している場合、それはオプションではありません。

于 2012-10-31T16:18:50.220 に答える
0

型を制御できる場合は、それらの抽象基本クラスを作成できます。そのクラスに仮想デストラクタを与えます。次に、std::vector<Object*>それを繰り返し処理して、オブジェクトから継承するものをすべて削除できます。

おそらく最初に vtable にヒットするstd::vector<void*>ため、実際の値へのポインターを使用して2 番目の時間を確保する必要があります。Object*ここでは、次のような 2 番目の仮想関数virtual void* ptr() { return &value; }が役立ちます。オブジェクトのサイズが必要な場合は、それも追加できます。

次のようなテンプレート パターンを使用できます。

template<typename T>
class ObjVal : public Object {
    public:
    T val;
    virtual void* ptr() { return &this->val; }
    virtual size_t size() { return sizeof(this->val); }
};

その後、一度だけ入力する必要があります。

これは、すべてのオブジェクトが vtable に対して少なくとも 1 つの余分なポインターを取得するため、特にメモリ効率が良くありません。

ただし、new int(3)アロケータはおそらく 4 バイト以上を使用するため、メモリ効率もあまり良くありません。その vtable ポインターの追加は、基本的に無料です。

于 2013-03-27T23:17:41.060 に答える
-1

複数のベクターを使用してください。API と対話するために周囲を維持しvector<void*>ます (これには、不均一な型の void* の連続したブロックが必要だと思いますか?) だけでなく、データを所有するvector<std::unique_ptr<int>>andも持っています。vector<std::unique_ptr<float>>intを作成するときは、メモリを所有するa をofnewにプッシュし、それを API 互換のとして貼り付けます。3 つの s を 1 つにまとめて、可能であればそれらのライフタイムが結び付けられるようにします (おそらくそうです)。unique_ptrvectorintvectorvoid*vectorstruct

変数の所有権を格納する単一のベクトルを使用してこれを行うこともできます。vector自分でロールする RAII 疑似、unique_ptrまたはshared_ptrカスタムの駆逐艦を使用するvectorもの、またはstd::function<void()>「バンドル」する構造体の駆逐艦が呼び出すもの、または何を持っているか。しかし、これらのオプションはお勧めしません。

于 2012-10-31T16:07:42.520 に答える