1

別のプロジェクトのコードを使用しようとしていますが、次の形式の構造体があります。

struct data{
   std::vector<sparse_array> cols,rows;
}

struct sparse_array {
   std::vector<unsigned int> idxs;
   std::vector<double> values;

   void add(unsigned int idx, double value) {
       idxs.push_back(idx);
       values.push_back(value);
   }
}

私のコードでは、次の行を使用してみました。

data prob;
prob.cols.reserve(num_cols);
prob.rows.reserve(num_rows);

// Some loop that calls
prob.cols[i].add(idx, value);
prob.rows[i].add(idx, value);

そして、値prob.rows[i].value[j]をファイルに出力すると、すべてゼロになります。しかし、resize代わりに使用するreserveと、読み取った実際の値が得られます。誰かがこれについて説明してもらえますか?

4

2 に答える 2

3

関数reserve()は、指定した数のアイテムを保持するのに十分な大きさのメモリの連続領域を割り当てるだけで、ベクターの古いコンテンツをこの新しいブロックに移動します。これにより、指定されている限り、挿入時にベクターのストレージの再割り当てが行われないようになります。容量を超えていません。この関数は、再割り当ての数を減らすために使用されます(これにより、イテレーターも無効になります)が、ベクトルの最後に新しい項目は挿入されません

C ++ 11標準、パラグラフ23.3.6.3/1からreserve()

計画されたサイズの変更をベクトルに通知し、それに応じてストレージ割り当てを管理できるようにするディレクティブ。の後はreserve()capacity()再割り当てが発生した場合の予約の引数以上になります。それ以外の場合は前の値と同じcapacity()です。現在の容量がの引数よりも小さい場合にのみ、この時点で再割り当てが発生しますreserve()。非型のmoveコンストラクタ以外で例外がスローされた場合、CopyInsertable影響はありません。

これを行うと、おそらく範囲外のインデックスであるため、未定義の動作prob.cols[i].push_back(idx, value);が発生する可能性があることに注意してください。i

一方、関数resize() ベクトルの最後にアイテムを挿入するため、ベクトルの最終的なサイズは指定したサイズになります(つまり、現在のサイズよりも小さいサイズを指定すると、要素を消去することもできます) 。の呼び出しに2番目の引数を指定しない場合resize()、新しく挿入されたアイテムは値で初期化されます。それ以外の場合は、指定した値からコピー初期化されます。

C ++ 11標準、パラグラフ23.3.6.3/9からresize()

の場合sz <= size()、;と同等erase(begin() + sz, end())です。の場合、値で初期化された要素をシーケンスsize() < szに追加 します。sz - size()

要約すると、呼び出し後にベクターにアクセスするresize()と期待される結果が得られる理由は、アイテムが実際にベクターに追加されているためです。一方、toを呼び出してreserve()もアイテムは追加されないため、存在しない要素に後でアクセスすると、未定義の動作が発生します

于 2013-02-24T01:54:53.117 に答える
0

ベクトルが空の場合、最後に新しい要素をstd::vector::resize(n)挿入して、このベクトルの内容を拡張します。ベクトルが要素を格納するために使用するメモリ ブロックのみを再割り当てし、要素を保持するのに十分な大きさにします。nstd::vector::reserve(n)n

次に、 を呼び出すとprob.cols[i]、 index の要素にアクセスしようとしていますi。以前に使用した場合reserve、これにより、要素がまだ存在しないメモリにアクセスすることになり、未定義の動作が生成されます。

したがってresize、この場合にのみ使用してください:)

于 2013-02-24T02:01:47.970 に答える