1

2 つのループによって出力されるアドレスが同じであるとは思いませんか? 私はそうでしたが、なぜ(時々)それらが異なるのか理解できません。

#include <iostream>
#include <vector>
using namespace std;

struct S {
  void print_address() {
    cout << this << endl;
  }
};

int main(int argc,char *argv[]) {
  vector<S> v;
  for (size_t i = 0; i < 10; i++) {
    v.push_back( S() );
    v.back().print_address();
  }
  cout << endl;
  for (size_t i = 0; i < v.size(); i++) {
    v[i].print_address();
  } 
  return 0;
}

このコードを多くのローカル コンパイラとオンライン コンパイラでテストしたところ、次のような出力が得られました (最後の 3 つの図は常に同じです)。

0xaec010
0xaec031
0xaec012
0xaec013
0xaec034
0xaec035
0xaec036
0xaec037
0xaec018
0xaec019

0xaec010
0xaec011
0xaec012
0xaec013
0xaec014
0xaec015
0xaec016
0xaec017
0xaec018
0xaec019

最初のループで初期化を行ったために、プログラムの後続部分で初期化されていないオブジェクトを取得したため、これを発見しました。何か不足していますか?

4

4 に答える 4

2

ベクトルは、必要に応じて拡大するために再割り当てを実行しています。これを行うたびに、データ用により大きなバッファが割り当てられ、要素がコピーされます。これは最初のループではっきりとわかります。ここでは、各アドレス ジャンプの後に、連続するアドレスのより大きなシーケンスが続きます。2 番目のループでは、最終的な再割り当て後のアドレスを確認するだけです。

0xaec010
0xaec031  <--
0xaec012  <--
0xaec013
0xaec034  <--
0xaec035
0xaec036
0xaec037
0xaec018  <--
0xaec019

ベクトルを 10 個Sのオブジェクトでインスタンス化する最も簡単な方法は次のとおりです。

std::vector<S> v(10);

これには、再割り当ては含まれません。も参照してくださいstd::vector::reserve

于 2013-08-13T10:01:14.620 に答える
1

ベクトル要素は連続して格納されます。つまり、それらはすべてメモリ内で一列に並んでいます。ベクター オブジェクトは、要素のこの連続ブロックにスペースを割り当てる必要があります。

ベクトルに無期限に何かを追加し続けることはできません。割り当てたスペースを拡張する必要があります。通常、メモリ モデルでは、メモリ ブロックを拡張することはできません。代わりに、新しいメモリ ブロックを作成する必要があります。ベクトルがこれを行うとき、そのすべての要素を新しいスペースに移動する必要があります。これは、最初のループ内で数回発生しています。

あなたがやった場合:

vector<S> v;
v.reserve(10);

(最終的に 10 個の要素になることがわかっているので、そうすることができます)、再割り当ては不要であり、アドレスは変更されませんでした。

于 2013-08-13T10:01:16.480 に答える
0

彼らが変わることができることに私は本当に驚かない。ベクトルには最初はサイズがないため、最初のループ中にベクトルが 1 回または 2 回再割り当てされる可能性があります。これにより、ベクターのベースアドレスが変更されます。サイズを変更した後、以前に使用していたアドレスを使用することになる可能性はあります (ただし、これは少し驚くべきことです。アドレスの最初の部分は確かですか?)

それらが変更されないようにしたい場合は、v.reserve()プッシュを開始する前に a を追加する必要があります。

于 2013-08-13T10:05:16.873 に答える