erratum: 前回の記事に関して

前回の記事を書いた2日後くらいに、よく考えると先のコードはまずいのではという気もちになった。今日まで放置していたのは、まず自分が書いていたコードを直すことと、書かなければならない書類をこなすことに集中していたからだ。書類は数日前に草稿を共著者に送りつけた。穴だらけだとわかっているので、そろそろまた仕事が帰ってくるだろうが、今この瞬間は少し落ち着けている。もっと仕事を早くこなせるようにならねばならない。

さて、何がまずいかもしれないかというと、まずstd::vectorは(C++17以前は)要素型Tが完全形であることを要求している。よって、以下のような型はおかしいのではないか。

struct X
{
    std::vector<X> xs;
};

ここで、struct Xの宣言が終わる最後の行まで、Xは完全形ではない。しかしその内部でstd::vector<X>を使っている。ここではまだXは不完全型ではないのか。

ところでこれは動く。X x; x.xs.resize(10);とかしても動く。そもそも気づかずに書いてしまった理由は、手元のいくつかのコンパイラで動いたからというのが大きい(C++erとしてはまだまだ未熟だ)。それに、書いているときはstd::vectorは内部的にはヒープにアロケートした配列へのポインタ、つまりここでX*のようなものを持っているに違いないと思っていたため、動くだろうと考えたのだった。

だが実際には上記のように、std::vectorなどコンテナの要素型は完全型でなければならない。ので上のコードが動いたのは、使ったSTL実装が動くようなものだったからで、つまるところ処理系依存な挙動をしたのだと思われる。ちなみに、C++17では不完全型のstd::vectorが作れるようになる。その代わり、アロケータ型が「アロケータ完全性要求」なるものを満たしている必要があるようだが。

よって、以上のような型を書いてはならず、C++17まで待つか、Boost.containerを使うとよい。これは不完全型をサポートしている。

上記リンクから飛ぶこともできるが、以下の記事で標準ライブラリと不完全型の話がなされている。http://www.drdobbs.com/the-standard-librarian-containers-of-inc/184403814