126

Scott Meyers の著書「Effective STL: 50 Specific Ways to Improvement Your Use of the Standard Template Libraryvector <bool> 」の項目 18 は、STL コンテナーではなく、実際には s を保持しないため、避けるように述べていboolます。

次のコード:

vector <bool> v; 
bool *pb =&v[0];

コンパイルされず、STL コンテナーの要件に違反します。

エラー:

cannot convert 'std::vector<bool>::reference* {aka std::_Bit_reference*}' to 'bool*' in initialization

vector<T>::operator []戻り値の型は であるはずですT&が、なぜ特殊なケースなのvector<bool>ですか?

実際には何がvector<bool>構成されていますか?

この項目はさらに次のように述べています。

deque<bool> v; // is a STL container and it really contains bools

これは の代替として使用できますvector<bool>か?

誰でもこれを説明できますか?

4

6 に答える 6

145

スペース最適化の理由から、C++ 標準 (C++98 までさかのぼる) はvector<bool>、各ブール値が通常のブール値のように 1 バイトではなく 1 ビットのスペースのみを使用する特別な標準コンテナーとして明示的に呼び出します (一種の「動的ビットセット」)。この最適化と引き換えに、通常の標準コンテナーのすべての機能とインターフェースを提供するわけではありません。

この場合、バイト内のビットのアドレスを取得できないため、 などをoperator[]返すことはできずbool&、代わりに問題の特定のビットを操作できるプロキシ オブジェクトを返します。このプロキシ オブジェクトは ではないため、「通常の」コンテナでこのような演算子を呼び出した結果と同様bool&に、そのアドレスを に割り当てることはできません。これは、有効なコードではないbool*ことを意味します。bool *pb =&v[0];

一方、そのdequeような特殊化が呼び出されていないため、各 bool はバイトを取り、から返される値のアドレスを取得できますoperator[]

最後に、MS 標準ライブラリの実装は、deque に小さなチャンク サイズを使用するという点で (ほぼ間違いなく) 最適ではないことに注意してください。

于 2013-07-22T18:39:42.390 に答える
29

問題は、真の参照ではなくプロキシ参照オブジェクトvector<bool>を返すため、C++98 スタイルのコードがコンパイルされないことです。ただし、最新の C++11は、プロキシ ポインター オブジェクトも返す場合にコンパイルすることができます。Howard Hinnant は、このようなプロキシ参照とポインターを使用する際のアルゴリズムの改善について詳述したブログ投稿を書きました。bool * p = &v[0];auto p = &v[0];operator&

Scott Meyers は、プロキシ クラスについて、より効果的な C++の長い記事 30 を持っています。組み込みの型をほとんど模倣するまでには長い道のりを歩むことができます。任意の typeTに対して、プロキシのペア (たとえばreference_proxy<T>、 と) は、とが互いの逆iterator_proxy<T>であるという意味で相互に一貫性を持たせることができます。reference_proxy<T>::operator&()iterator_proxy<T>::operator*()

ただし、ある時点で、プロキシ オブジェクトをマップして、T*またはのように動作させる必要がありますT&。イテレータ プロキシの場合、すべての機能を再実装しなくてもoperator->()、テンプレートのインターフェイスをオーバーロードしてアクセスできます。Tただし、参照プロキシの場合は をオーバーロードする必要がありoperator.()、現在の C++ では許可されていません ( BoostCon 2013 でSebastian Redlがそのような提案を提示しましたが)。.get()参照プロキシ内のメンバーのような冗長な回避策を作成するか、参照内のすべてTの のインターフェイスを実装できます (これは、vector<bool>::bit_reference)、ただし、これにより、組み込み構文が失われるか、型変換の組み込みセマンティクスを持たないユーザー定義変換が導入されます (引数ごとに最大 1 つのユーザー定義変換を使用できます)。

TL;DR :vector<bool>標準では実際の参照が必要なため、no はコンテナーではありませんが、少なくとも C++98 よりも C++11 (auto) の方がコンテナーのように動作するようにすることができます。

于 2013-07-22T21:14:58.453 に答える
16

多くの人は、vector<bool>専門化は間違いだと考えています。

論文「Deprecating Vestigial Library Parts in C++17」では、 Reconsider vector Partial Specialization
への提案があり ます。

std::vector の bool 部分特殊化がコンテナーの要件を満たしていないという長い歴史があり、特に、その反復子がランダム アクセス反復子の要件を満たしていません。このコンテナーを非推奨にする以前の試みは、C++11、N2204で拒否されました。


拒否の理由の 1 つは、テンプレートの特定の特殊化を非推奨にすることが何を意味するのかが明確でないことです。それは、慎重な言葉遣いで対処することができます。より大きな問題は、ベクトルの (パックされた) 特殊化が、標準ライブラリのクライアントが真に求めている重要な最適化を提供することですが、もはや利用できないことです。N2050などの代替機能が提案され、受け入れられるまで、標準のこの部分を非推奨にすることはできそうにありません。残念ながら、Library Evolution Working Group に現在提供されているそのような改訂された提案はありません。

于 2016-02-29T09:10:20.317 に答える