コンテナの初期化

最初からコンテナに入れたい初期値となるデータがある場合はどうやるのが効率がいいんだろう。コンストラクタの定義を見ると、値を指定した場合すべての要素が同じその値で初期化されてしまうようだ。別のコンテナからコピーしてくる方法はあるようだけど、それだとコピー元のコンテナをまず初期化しなければいけないので結局問題は解決されない。配列のように初期化で値が書けるといいんだけど。


STL標準講座―標準テンプレートライブラリを利用したC++プログラミング (Programmer’s SELECTION)
STL標準講座」という本を見てみると、配列をリストにコピーする例が書いてある。これだ。
しかし、copy()の第2引数はend()の要素、つまりコンテナの最後の要素の次を入れるようになっている。このコードでも10個の要素を持った配列numsを用意し、copyの第2引数には&nums[9]を入れている。そしてその結果はnums[8]までがコピーされている。最後の要素はコピーされないのか。まあ、ひとつ余分な最後を表す要素を入れておけばいいので、かまわないと言えばかまわないのでけど、なんとなくすっきりしないかな……


C++ プライマー 第4版 IT Architect’ Archive クラシックモダン・コンピューティング (IT Architects’ Archive―CLASSIC MODERN COMPUTING)
と思って今度は「C++プライマー」という本を見てみると、ちゃんと初期化について書かれている。さすが厚いだけあるぜ。

ポインタはイテレータであるから、組み込み型配列を指す一対のポインタでコンテナを初期化できても驚くには当たらない。


char *words[] = {"stately", "plump", "buck", "mulligan"};
// wordsの要素数を計算する
size_t words_size = sizeof(words)/sizeof(char *);
// 配列全体を使ってwords2を初期化する
list words2(words, words + words_size);


ここで、sizeof(5.8節、p.193)を使って配列の大きさを計算している。配列の先頭を指すポインタと、出外れポインタをアーギュメントとして渡している。

「驚くに当たらない」という微妙に場違いな感じのする語感が好きだ。
それは置いておいて、出外れポインタって何? イテレータのend()が指すところと同じような、最後の要素の次を指すポインタだろうと想像はつくけど、一般的な言葉なのかな? そして配列でもそれはありなのか?


この本の「配列とポインタ」の章にはこうある。

ポインタ算術が合法なのは、元のポインタと新しく求めたポインタが同じ配列の中の要素を指しているか、出外れポインタであるときに限る。

配列あるいは一般にオブジェクトの直後のアドレスを求めることは合法である。そういうアドレスを持つポインタを参照剥がしすることは違法である。また、直後よりさらに先のアドレス、または、配列の先頭より手前のアドレスを求めるのも違法である。

ああ、そういえば微かな記憶が。Cの知識だな。今手元にはC++の本しかないのだけど、これらを探してもこの事は書いてなかった(もちろん探し方が悪いのかもしれない)。
そうか。イテレータのend()みたいなのはポインタ計算でもあったのか。そういえばあったよなあ。すっかり記憶から消えていたけど。


Modern Classics Ulysses (Penguin Modern Classics)
ところでさっきの例題に出てきた文字列、"stately", "plump", "buck", "mulligan"ってなんだろうと思って調べてたら、ジェイムズ・ジョイスの「ユリシーズ」の冒頭だった。なぜここに? ずいぶん高尚だな。
"Stately, plump Buck Mulligan came from the stairhead, bearing a bowl of lather on which a mirror and a razor lay crossed."