web-dev-qa-db-ja.com

libc ++のvector <bool> :: const_referenceがboolではないのはなぜですか?

セクション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 ++はlibc ++の最初の導入以来一貫してこの仕様に従っていないことに注意してください。

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

91
Howard Hinnant

この拡張の動機は、適合プログラムによって検出可能であり、したがって不適合であるため、vector<bool>を参照(constなど)に関して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!とマークされたアサートはトリガーされますが、testvector<bool>で実行される場合のみです。 vector<char>(またはvector以外の適切なboolが適切なデフォルト以外のTが割り当てられているときに実行すると、テストに合格します。

Libc ++実装では、汎用コードでvector<bool>が異なる動作をすることによる悪影響を最小限に抑えようとしました。これを実現するためにしたことの1つは、指定されたvector<T>::const_referenceと同様に、vector<T>::referenceproxy-referenceにすることです。ただし、それ。つまり、libc ++では、vector<T>::const_referenceは基本的に、そのビットのコピーではなく、vector内のビットへのポインターです。

Libc ++では、上記のtestvector<char>vector<bool>の両方に渡されます。

費用は?

欠点は、質問に示されているように、この拡張機能が検出可能であることです。ただし、実際にはこのエイリアスの正確なタイプを気にするプログラムはほとんどなく、動作を気にするプログラムも増えています。

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

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

このような提案は、現在のbit_vectorとほぼ同じAPIを備えた新しいコンテナ(たとえばvector<bool>)の形で提供されますが、ここで説明するconst_referenceなどのいくつかのアップグレードがあります。 vector<bool>スペシャライゼーションの廃止(および最終的な削除)が続きます。 bitsetは、この部門で少しアップグレードすることもできます。 const_referenceとイテレータのセットを追加します。

つまり、bitsetarrayであるように、後知恵ではvectorvector<bool>になります(bit_vectorに変更する必要があります)。そして、boolvectorvalue_typeとしてarrayについて話しているかどうかにかかわらず、類推は真実である必要があります。

Libc ++の拡張機能として開始されたC++ 11およびC++ 14機能の例は複数あります。これが標準の進化です。実際の実証済み肯定的現場経験は強い影響を及ぼします。標準の人々は、既存の仕様を変更することになると、保守的な束になります(そうあるべきです)。推測は、正しく推測していると確信している場合でも、国際的に認められた標準を進化させるためのリスクの高い戦略です。

98
Howard Hinnant