3

この質問は、次のトピックから派生しています。

ベクトル予約 c++

タイプのデータ構造を使用していvector<vector<vector<double> > >ます。double項目 ( ) が追加される前に、これらの各ベクトル (外側のベクトルを除く) のサイズを知ることはできません。各「ディメンション」のアイテム数のおおよそのサイズ (上限) を取得できます。

vector<vector<vector<double> > >共有ポインタを使用したソリューションが最適な方法かもしれませんが、単に.reserve()十分なスペースを確保した (または他の方法で十分なメモリを割り当てた)ソリューションを試してみたいと思います。

A.reserve(500)[1000][10000] などの大きなサイズの「2D」ベクトルを保持するには (サイズが 500 であるか、サイズの上限であると仮定して) 十分でしょうか?

私の質問の主な理由はA、 の時点での内部のサイズを合理的に見積もる方法が見当たらないからです.reserve(500)

私の質問の例:

vector<vector<vector<int> > > A;
A.reserve(500+1);
vector<vector<int> > temp2;
vector<int> temp1 (666,666);
for(int i=0;i<500;i++)
{
  A.push_back(temp2);
  for(int j=0; j< 10000;j++)
  {
    A.back().push_back(temp1);
  }
}

これにより、A の再割り当てが行われないことが保証されますか?

temp2.reserve(100000)とが作成時に追加された場合、temp1.reserve(1000)これにより、再割り当てがまったく発生しないことが保証されますか?

.reserve()上記では、保守的な呼び出しが原因でメモリが浪費される可能性があるという事実を無視してください。

よろしくお願いします!

4

10 に答える 10

1

あなたの例は多くのコピーと割り当てを引き起こします。

vector<vector<vector<double>>>  A;
 A.reserve(500+1);
 vector<vector<double>>  temp2; 
vector<double> temp1 (666,666);
 for(int i=0;i<500;i++) 
{
 A.push_back(temp2);
 for(int j=0; j< 10000;j++)
 {
 A.back().push_back(temp1);
 }
} 

Q:これにより、Aの再割り当てが行われないようになりますか?
A:はい。

Q:作成時に追加されたtemp2.​​reserve(100000)とtemp1.reserve(1000)が、再割り当てがまったく発生しないことを保証しますか?
A:ここで、temp1は作成時に自身の長さをすでに認識しており、変更されないため、temp1.reserve(1000)を追加すると、不要な再割り当てのみが強制されます。
この例では、A.back()。reserve(10000)を使用して、ベクタークラスがコピーコンストラクターで何をコピーするかわかりません。
更新: g ++でテストしたばかりで、temp2の容量はコピーされません。したがって、temp2.​​reserve(10000)は機能しません。

また、コードを投稿するときはソース形式を使用してください。読みやすくなります:-)。

于 2010-02-28T16:08:35.993 に答える
1

ある日、同じ問題が発生しました。これを行うためのクリーンな方法(私は思う)は、独自に作成Allocatorし、それを内部ベクトル(の最後のテンプレートパラメーターstd::vector<>)に使用することです。アイデアは、実際にはメモリを割り当てず、外部ベクトルのメモリ内に正しいアドレスを返すだけのアロケータを作成することです。以前の各ベクトルのサイズがわかれば、このアドレスを簡単に知ることができます。

于 2010-03-01T17:56:32.343 に答える
1

このreserve関数は適切に機能しますが、とvector Aは期待どおりに機能しません。temp1temp2

temp1ベクターは特定のサイズで初期化されるため、適切なサイズで設定され、サイズを大きくしない限り、これcapacityを使用する必要はありません。reserve

に関してtemp2は、capacity属性はコピーに引き継がれません。関数を使用するたびにpush_back、コピーを に追加することを考慮するとvector、次のようなコード

vector<vector<double>> temp2;
temp2.reserve(1000);
A.push_back(temp2); //A.back().capacity() == 0

すぐに割り当てが解除される一時に割り当てられたメモリを増やしているだけで、期待どおりにvector要素の容量を増やしていません。本当にソリューションとして使用したい場合は、次のようにする必要がvectorありますvector

vector<vector<double>> temp2;
A.push_back(temp2);
A.back().reserve(1000); //A.back().capacity() == 1000
于 2010-02-28T16:25:44.083 に答える
1

[1000][1000] に対して、事前に A に 500 エントリを予約することはどのようにできますか?

A に対して > 1000 を予約する必要があります (これは実際の上限値です)。次に、A にエントリを追加するたびに、別の 1000 程度を予約する必要があります (これも上限ですが、2番目の値です)。

すなわち

A.reserve(UPPERBOUND);

for(int i = 0; i < 10000000; ++i)
   A[i].reserve(UPPERBOUND);

ところで、予約はバイト数ではなく要素数を予約します。

于 2010-02-28T15:50:09.897 に答える
1

などのデータ構造のコピーと再割り当てを避けるためにvector<vector<vector<double> > >、次のことをお勧めします。

vector<vector<vector<double> > > myVector(FIXED_SIZE);

値を「割り当てる」ために、必要な次元が実際にわかるまで内部ベクトルを定義しないでください。次に、割り当ての代わりに swap() を使用します。

vector<vector<double> > innerVector( KNOWN_DIMENSION );
myVector[i].swap( innerVector );

push_back()はコピー操作を実行し、再割り当てを引き起こす可能性があることに注意してくださいswap()(両方のベクトルに同じアロケーター タイプが使用されていると仮定して)。

于 2010-04-08T12:02:27.773 に答える
0

マトリックスが本当に大きくて余裕がある場合は、スパース マトリックス ライブラリも試してみます。それ以外の場合は、アロケーターをいじる前に、vector を deque に置き換えてみます。両端キューは成長しても再割り当てされず、ベクターとほぼ同じくらい高速なランダム アクセスを提供します。

于 2010-04-16T17:26:35.803 に答える
0

これは多かれ少なかれここで答えられました。したがって、コードは次のようになります。

vector<vector<vector<double> > > foo(maxdim1,
    vector<vector<double> >(maxdim2,
    vector<double>(maxdim3)));
于 2010-05-07T15:11:46.023 に答える
0

ベクトルをネストする代わりに、実際の行列クラスが必要なようです。いくつかの強力な疎行列クラスを持つブーストを見てください。

于 2010-02-28T16:49:25.407 に答える
0

さて、私は自分でいくつかの小規模なテストを行いました。http://www.tek-tips.com/faqs.cfm?fid=5575から取得した「2DArray」を使用して、メモリを静的に割り当てる構造を表しました。動的割り当てには、元の投稿で示されているようにベクトルを使用しました。

次のコードをテストしました (hr_time は Web で見つかったタイミング ルーチンであり、残念ながらスパム対策のために投稿できませんが、提供してくれた David Bolton の功績によるものです)。

#include <vector>
#include "hr_time.h"
#include "2dArray.h"
#include <iostream>
using namespace std;

int main()
{
    vector<int> temp;

    vector<vector<int> > temp2;

    CStopWatch mytimer;

    mytimer.startTimer();

    for(int i=0; i<1000; i++)
    {
        temp2.push_back(temp);
        for(int j=0; j< 2000; j++)
        {
            temp2.back().push_back(j);
        }
    }

    mytimer.stopTimer();

    cout << "With vectors without reserved: " << mytimer.getElapsedTime() << endl;

    vector<int> temp3;

    vector<vector<int> > temp4;

    temp3.reserve(1001);

    mytimer.startTimer();

    for(int i=0; i<1000; i++)
    {
        temp4.push_back(temp3);
        for(int j=0; j< 2000; j++)
        {
            temp4.back().push_back(j);
        }
    }

    mytimer.stopTimer();

    cout << "With vectors with reserved: " << mytimer.getElapsedTime() << endl;

    int** MyArray = Allocate2DArray<int>(1000,2000);

    mytimer.startTimer();
    for(int i=0; i<1000; i++)
    {
        for(int j=0; j< 2000; j++)
        {
            MyArray[i][j]=j;
        }
    }


    mytimer.stopTimer();

    cout << "With 2DArray: " << mytimer.getElapsedTime() << endl;

    //Test
    for(int i=0; i<1000; i++)
    {
        for(int j=0; j< 200; j++)
        {
            //cout << "My Array stores :" << MyArray[i][j] << endl;
        }
    }

    return 0;
}

これらのサイズには約 10 倍の係数があることがわかります。したがって、速度が最も重要であるため、動的割り当てがアプリケーションに適しているかどうかを再検討する必要があります!

于 2010-03-01T17:28:29.913 に答える
0

コンストラクターで内部コンテナーと reserve() をサブクラス化しないのはなぜですか?

于 2010-03-17T00:09:55.983 に答える