1. ホーム
  2. c++

[解決済み] libc++ の vector<bool>::const_reference はなぜ bool ではないのですか?

2023-03-01 20:43:59

質問

23.3.7節 クラス vector<bool> [vector.bool]の第1段落に記載されています。

template <class Allocator> class vector<bool, Allocator> {
public:
    // types:
    typedef bool              const_reference;
    ...

しかし、このプログラムはlibc++を使用した場合、コンパイルに失敗します。

#include <vector>
#include <type_traits>

int
main()
{
    static_assert(std::is_same<std::vector<bool>::const_reference, bool>{}, "?");
}

さらに私は、C++ 標準が C++98 までずっとこの仕様で一貫していることに注目しています。 そして、さらに私は、libc++ が最初に導入されて以来、一貫してこの仕様に従わないことに注目します。

この非適合性の動機は何でしょうか。

どのように解決するのですか?

この拡張は、適合するプログラムによって検出可能であるため、不適合とする動機は vector<bool> のような振る舞いをすることです。 vector<char> のように振る舞います。

導入

1998年から vector<bool> は、「コンテナとは言えない」と揶揄されてきました。 LWG 96 は、最初の LWG の問題の 1 つで、この議論を開始しました。 それから 17 年後の今日 vector<bool> はほとんど変化していません。

この論文 の動作について、いくつかの具体的な例を挙げています。 vector<bool> の他のすべてのインスタンスとどのように違うのか、具体的な例を挙げています。 vector は他のすべてのインスタンス化と異なるため、ジェネリックコードに支障をきたします。 しかし、同じ論文で、非常に優れたパフォーマンス特性である vector<bool> が適切に実装されていれば、非常に優れたパフォーマンス特性を発揮することができます。

概要

: vector<bool> は悪いコンテナではありません。実際かなり便利です。 ただ、名前が悪いだけだ。

に戻る const_reference

上記で紹介したように の詳細はこちら の何が悪いのでしょうか? vector<bool> の悪いところは、ジェネリックコードの中で他の vector のインスタンス化とは異なる動作をするということです。 以下はその具体例です。

#include <cassert>
#include <vector>

template <class T>
void
test(std::vector<T>& v)
{
    using const_ref = typename std::vector<T>::const_reference;
    const std::vector<T>& cv = v;
    const_ref cr = cv[0];
    assert(cr == cv[0]);
    v[0] = 1;
    assert(true == cv[0]);
    assert(cr == cv[0]);  // Fires!
}

int
main()
{
    std::vector<char> vc(1);
    test(vc);
    std::vector<bool> vb(1);
    test(vb);
}

標準仕様では、アサートマーク付きの // Fires! がトリガーされますが、それは test が実行されたときのみです。 vector<bool> . で実行された場合 vector<char> (または任意の vector の他に bool を使用すると、適切な非デフォルトの T が割り当てられている場合)、テストはパスします。

libc++ の実装では、テスト時に vector<bool> が一般的なコードで異なる振る舞いをすることの弊害を最小限にしようとしました。 これを達成するために行ったことのひとつが vector<T>::const_reference a プロキシリファレンス と同じように、指定された vector<T>::reference と同じですが、これを通して代入できないことを除けば、です。 つまり、libc++上では vector<T>::const_reference の中のビットへのポインタです。 vector の中のビットへのポインタであり、そのビットのコピーではありません。

libc++では、上記の test の両方が通過します。 vector<char>vector<bool> .

どんなコストで?

欠点は、質問にあるように、この拡張が検出可能であることです。 しかし、実際にこのエイリアスの正確な型を気にするプログラムは非常に少なく、より多くのプログラムが動作を気にしています。

この不適合に対する動機は何ですか?

libc++ クライアントに汎用コードでのより良い動作を与え、おそらく十分なフィールドテストの後、C++ 業界全体の改善のために将来の C++ 標準にこの拡張機能を提案すること。

このような提案は、新しいコンテナ (例えば bit_vector と同じ API を持つ新しいコンテナ (例: ) のような形になるかもしれません。 vector<bool> とほぼ同じですが、いくつかのアップグレードがなされています。 const_reference のようなアップグレードが必要です。 その後、非推奨 (そして最終的には削除) である vector<bool> の特殊化を推奨します。 bitset はまた、この部門で少しアップグレードを使うことができます。 const_reference とイテレータのセットを追加します。

つまり、今思えば bitsetvector<bool> (にリネームされるべきです)。 bit_vector -- などに変更する必要があります。 arrayvector . について話しているかどうかに関わらず、この類推は成り立つはずです。 boolvalue_typevectorarray .

C++11 や C++14 の機能が libc++ の拡張機能としてスタートした例は複数あります。 このように標準は進化していくのです。 実際の が実証した ポジティブ 現場での経験は強い影響力を持ちます。 既存の仕様を変更することに関しては、標準の専門家は保守的な集団です (そうあるべきです)。 推測は、たとえ自分が正しく推測していると確信している場合でも、国際的に認められた標準を進化させるためには危険な戦略です。