読者です 読者をやめる 読者になる 読者になる

自作コンテナを作ろうとしたらboostにあった話

C++ ポエム

タイトルで全てを言い切ったので今日の日記は終わりです。嘘です。でもマジで書くことがない。

発端は、std::vectorが遅い(のでたいてい足りるくらいの要素数のグローバル生配列を使う! というのはかなり極限的なダーティハックだと思うのだが、界隈ではたまに聞く)という話をちょいちょい聞くことだ。個人的には、メモリ再確保をそう頻繁にしないなら、要するにヒープにメモリ確保したあとそれを使っているに過ぎないので、そんなに騒ぐようなことか、と思う。ヒープメモリアクセスとスタックメモリアクセスには大抵の場合気になるような実行時コスト差はないと思うのだが、処理系によっては違うかもしれないし、実際にメモリ再確保がなんだかんだ結構頻繁に起きる場合は普通に遅くなる。しかしこれはそもそもヒープでのメモリ確保が結構高コストな処理だからで、別にstd::vectorが大量のオーバーヘッドを抱えて不当に遅くしているというわけではない。ここでstd::vector::atとかは安全性と速度のトレードオフを意識してユーザーが選ぶべき選択肢なので、atを使うと遅い、というのは何言ってんだお前の一言に尽きてしまう。というか速度を重視するC++でここまで広く使われてるクラスの(よく使われる、GCCとかの)実装が最適化されてないということは考え難いだろうとも思える。

これが特殊な環境でベンダーが提供してるSTL実装が不当に遅いとかそういう理由なら、それはstd::vectorの責任というよりはSTL実装を提供している側の責任という気がするので、「C++std::vectorは遅い」というのは(普通の環境では起きないという意味で)言葉足らずだしどちらかというとデマに近いと思うのだが。まあそれを言い出すと「std::vectorの〇〇実装〇〇という環境で〇〇に比較すると遅い」の斜体部分がない言説が果たして意味をなすのかという話ではある。

(ただ、const参照渡しをするべきところでコピー渡しをすると配列の先頭ポインタのコピー渡しよりも遅いとか、ループ中でstd::vectorを作っては壊しすると遅いとか、そういうのは単に書き方の問題なので、その場合std::vectorが遅いのではなくそのユーザーの書くコードが遅いだけである。裏で何が起こるかを勉強する気はないのに速さも安全性も書きやすさもほしいというのはかなり強欲なのではないか。ほとんど何も勉強しなくてもそのうち少なくとも1つはC++は与えてくれる。相反する複数の欲求を同時に叶えたいならユーザーもある程度の出費は覚悟するべきなのではないだろうか)

まあそういうことは置いておいても、C++erを自称する身としては「そんなに言うなら内部的には組み込み配列に等しいstd::arrayのやり方でstaticにメモリ確保して、インターフェースはあたかもstd::vectorであるかのように見せるクラスを作ればいいのでは」、と発想するのは自然な流れだろう。というわけでlimited_vectorと命名したクラスの要件を書き出して実装を考え始めたあたりで「いやこれ絶対あるよな……」と思って検索してみたところ、案の定boost::container::static_vectorなるコンテナが存在し、似たようなことをしていることが判明した。これはboost::container::vectorを継承しており、最初に最大要素数分だけのメモリを確保しておき、後でそこを埋めていく形を取っている。なので中身的にはstd::arrayよりもstd::vectorに近いかと思った。一応今回の目的とは違うっぽいのでlimited_vectorの実装の続きをしてもいいのだが、否定的に示すための実装はあまり気が乗らないので放置している。