web-dev-qa-db-ja.com

C ++ 20でstd :: ssize()が導入されたのはなぜですか?

C++ 2 以下のstd::ssize() free関数を導入しました:

_template <class C>
    constexpr auto ssize(const C& c)
        -> std::common_type_t<std::ptrdiff_t,
                              std::make_signed_t<decltype(c.size())>>;
_

可能な実装は_static_cast_を使用して、class Csize()メンバー関数の戻り値を変換するようですその署名された対応物。

Cのsize()メンバー関数は常に非負の値を返すので、なぜ誰もがそれらを符号付き変数に格納したいのでしょうか?本当にしたい場合、それは単純な_static_cast_の問題です。

なぜstd::ssize()がC++ 20で導入されたのですか?

96
John Z. Li

理論的根拠は このペーパー で説明されています。見積もり:

SpanがC++ 17に採用されたとき、インデックスとサイズの両方として符号付き整数を使用しました。部分的には、コンパイル時にサイズが不明な型を示すセンチネル値として「-1」を使用できるようにするためでした。ただし、size()関数が符号付きの値を返すSTLコンテナを使用すると問題が発生するため、P1089を導入して問題を「修正」しました。多数の支持を得たが、コンセンサスに必要な2対1のマージンは受けなかった。

このペーパーP1227は、非メンバーstd :: ssizeおよびメンバーssize()関数を追加する提案でした。これらを含めると、特定のコードがはるかに簡単になり、サイズの計算で不要な符号なしの回避が可能になります。アイデアは、std :: ssize()とメンバー関数の両方でssize()をすべてのコンテナで使用できるようにすると、P1089への抵抗が減少するというものでした。

68
Nadav Har'El

感謝の気持ち 盗まれた Eric Nieblerから:

'Unsigned types signal that a negative index/size is not sane'は、STLが最初に設計されたときの一般的な知恵でした。しかし、論理的には、物事の数はポジティブである必要はありません。コレクションに追加またはコレクションから削除された要素の数を示すために、符号付き整数でカウントを保持したい場合があります。次に、それをコレクションのサイズと組み合わせます。コレクションのサイズが符号なしの場合、バグファームである符号付き演算と符号なし演算の混合を余儀なくされます。コンパイラーはこれについて警告しますが、STLの設計がプログラマーをこの状況に強制するので、ほとんどの人は警告をオフにします。これは本当のバグを隠すので残念です。

インターフェイスで符号なしintを使用することは、多くの人がそうだと考える恩恵ではありません。偶然にユーザーがAPIにわずかに負の数を渡すと、突然大きな正の数になります。 APIが番号を署名済みとみなした場合、番号がゼロ以上であることをアサートすることで状況を検出できます。

署名されていないintの使用をビット調整(マスクなど)に制限し、他のすべての場所で署名されたintを使用すると、バグが発生する可能性が低くなり、バグの発生を検出しやすくなります。

45
sp2danny