Help us understand the problem. What is going on with this article?

C++ vector::reserveの挙動を勘違いしていた件について

More than 5 years have passed since last update.

vector・stringのメンバ関数であるreserve関数の挙動を勘違いしてた。私のようによく知りもせずに使うとハマってしまうかもしれない。そもそもreserve関数で確保される容量(capacity)とは何なのか?要素数(size)とは何が違うのか?

容量(capacity) / 要素数(size)とは

  • 容量とは要素を新たに挿入しても動的なメモリ確保が行われない 許容量 のこと
  • 要素数とは実際にコンテナに格納されている要素の数のこと

容量(capacity) / 要素数(size)の注意点

  • 容量を確保するのであって要素数を大きくする訳ではない
  • イテレータendは動かずにbeginと同じ位置を指したまま
  • 容量を確保したからといって要素数以上の位置にアクセスすべきではない

また、容量が足りなくなるとvector・stringは その時点での2倍の大きさ の容量を用意してくれるので、名著Effective STLの第14項「reserve を使って不必要な割り当てを避けよう」でも示されているように下手をすれば"無駄に何度もメモリ確保関数を呼び出す遅いコード"や"無駄に長い容量を確保させて邪魔くさいコード"になってしまうので注意するべき。
ここで、以下に私が実際に書いた 書くべきでないコード(恥) を晒す。

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;
const int N = 100;
int main(void) {
  vector<int> v;
  v.reserve(N);
  fill(v.begin(), v.end() + N, 1);

  cout << "size " << v.size() << endl;
  if (v.begin() == v.end())
    for (int i = 0; i < N; i++)
      cout << v[i];
  return 0;
}

10行目でvector::end()イテレータを無理やりに書いて気持ち悪いかもしれません、大変申し訳ない
fill関数で要素数以上の位置(v.size()==0なのに添字で言えば0~N-1)にアクセスしてるのが宜しくない、fill関数を使いたいのであれば

// 省略
  v.resize(N);
  fill(v.begin(), v.end(), 1);
// 省略

と書くべき。また、別の書き方としてはコンストラクタを用いて

// 省略
  vector<int> v(N, 1);
// 省略

と書くこともできる。

つまり

事前に要素数が分かっていて

  • push_back関数などで要素を一つずつ挿入したい場合はreserve関数
  • 添字アクセスにより任意の位置に要素を代入したい場合はresize関数 or vector( size_type size )コンストラクタ
  • 特定の値を敷き詰めたい場合はresize関数+fill関数 or vector( size_type num, const TYPE &val )コンストラクタ

とすれば良い。

謝辞

hattorixさん、skonbさん、h2so5さん、ご指摘頂きまして本当にありがとうございます。
根本的に勘違いしていました、これをキッカケにEffective C++・STLを読み直そうかと思います。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした