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


99

C ++ 20std::ssize()は以下のように無料関数を導入しました:

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

可能な実装はcl ass Cのメンバー関数のstatic_cast戻り値を対応する符号付きに変換するためにを使用しているようです。size()

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

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


4
@ Jarod42実装は未定義ではなく定義されていませんか?(署名されたオーバーフローは未定義であるが、署名された変換は、実装定義されている。)
ホーン

8
ssizeof演算子も追加した場合のみです。
geza

3
これは多少関連があるかもしれません:stackoverflow.com/questions/30395205/...
Marco13

10
@ JohnZ.Li説得力のないように聞こえるリスクがあります。整数型に関するC ++の型システム全体が壊れていると思います。もちろん、いくつかの癖(aのビット数がわからないなどchar)はCから継承されており、少なくともによって多少は軽減されると主張できますが、(u)intX_tそれでも、同様に微妙重大なバグの無限の原因です。のようなものssizeは単なるパッチであり、これが人々が(厳密に)従うことができる一般的な「ベストプラクティスガイド」に陥るまでには(おそらく「永久に」)時間がかかります。
Marco13

6
@ Marco13:一方、C / C ++型システム(Javaの固定型システムとは対照的に)は、他のほとんどの言語が不規則であるアーキテクチャでC / C ++コードが機能することを許可することを除い有能なインストラクターが重要なものを取得できるようにします学生の頭の中へのレッスン。同様に、すべての世界が64ビットであるとは限りません。いいえ、世界中で8ビット文字が使用されているわけではありません。これらのことに対処するのは非常に簡単あり、インストラクターだけが最初からこれを教えてくれれば、あなたはより良い開発者になります。(そして、念のために言うと、(u)intX_t型がオプションであることを知っていますか?)
DevSolar

回答:


69

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

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

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


30
このfor(int i = 0; i < container.ssize() - 1; ++i)例もかなり説得力があります
Caleth

7
@Johnは、実際にはstring :: nposと同じことを実行でき、特別な値としてsize_t(-1)を使用できるように思えます。
rubenvb

15
@ JohnZ.Li STLサイズタイプが署名されていないことは、長い間誤りと見なされてきました。現在、残念ながらそれを改革するには遅すぎます。無料の機能を提供することは、現時点で私たちができる最善のことです。
LF

16
@LF:カンファレンスでのハーブサッターだった(たぶんBjarneもこれを言った)。しかし、彼は少し間違っています。現在、32ビット/ 64ビットのコンピューターでは、署名されたサイズのほうが優れています(したがって、彼は正しいです)。しかし、昔(16ビットサイズ)では、符号付きサイズは悪かったでしょう(たとえば、32kバイトの配列のみを割り当てることができました)。
geza

11
@LF:ハーブがこれについて言及しているのを見つけました:youtube.com/watch ?v=Puio5dly9N8&t=2667 。「実際にはあまり出てこない」と彼が言ったとき、それは今日では真実です。しかし、20年以上前(16ビットシステム)にはまったく当てはまりませんでした。したがって、STLが設計されたとき、unsignedを使用することはそれほど間違いではありませんでした。
geza

50

無償で盗まれたエリックNieblerから:

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

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

符号なし整数の使用を少しいじる(マスクなど)に制限し、他のすべての場所で符号付き整数を使用すると、バグが発生する可能性が低くなり、バグが発生したときに簡単に検出できます。


6
Swiftはこのアプローチをとりますが、負の符号付き数値が大量の符号なし数値として再解釈される心配はありません(暗黙のキャストがないため、最初はこのクレイジーな楽しい家にあなたを連れて行きます)。Int正の数しか意味がない場合(配列のインデックス付けなど)でも、(マシンワードサイズ)が整数の一般的な通貨タイプである必要があります。それからの逸脱は十分に立証されるべきです。どこでもキャストについて心配する必要がないのはいいことです。
アレクサンダー-モニカを

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.