Mengapa std :: ssize () diperkenalkan di C ++ 20?

99

C ++ 20 memperkenalkan std::ssize()fungsi gratis seperti di bawah ini:

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

Sebuah implementasi yang mungkin tampaknya menggunakan static_cast, untuk mengubah nilai kembali dari size()fungsi anggota cl ass C menjadi mitra yang ditandatangani.

Karena size()fungsi anggota C selalu mengembalikan nilai non-negatif, mengapa ada orang yang ingin menyimpannya dalam variabel bertanda? Jika seseorang benar-benar menginginkannya, ini masalah sederhana static_cast.

Mengapa std::ssize()diperkenalkan di C ++ 20?

John Z. Li
sumber
4
@ Jarod42 Bukankah implementasi itu didefinisikan sebagai ganti undefined? (limpahan yang ditandatangani tidak ditentukan. tetapi konversi yang ditandatangani adalah implementasi yang ditentukan)
phön
8
Kalau saja mereka menambahkan ssizeofoperator juga.
geza
3
Ini mungkin agak terkait: stackoverflow.com/questions/30395205/…
Marco13
10
@ JohnZ.Li Beresiko terdengar terlalu tidak konstruktif: Saya pikir seluruh sistem tipe C ++ mengenai tipe integer rusak. Tentu, orang dapat berargumen bahwa beberapa kebiasaan (seperti tidak mengetahui berapa banyak bit yang chardimiliki) diwarisi dari C dan setidaknya diringankan oleh (u)intX_t, tetapi itu masih merupakan sumber bug yang sama-sama halus dan kritis tanpa akhir. Hal-hal seperti ssizeitu hanyalah tambalan, dan akan memakan waktu (mungkin "selamanya") sampai ini masuk ke dalam "panduan praktik terbaik" umum yang (dapat) diikuti orang dengan ketat.
Marco13
6
@ Marco13: Di sisi lain, sistem tipe C / C ++ (sebagai lawan dari misalnya sistem tipe tetap Java), selain mengizinkan kode C / C ++ untuk bekerja pada arsitektur di mana sebagian besar bahasa lain tidak jelas , memungkinkan instruktur yang kompeten untuk mendapatkan beberapa yang penting pelajaran ke kepala siswa. Seperti, tidak semua dunia 64bit. Dan tidak, tidak semua dunia menggunakan karakter 8-bit. Sangat mudah untuk mengatasi hal-hal ini, dan itu membuat Anda menjadi pengembang yang lebih baik, jika hanya instruktur yang akan mengajarkan ini dari awal . (Dan, hanya untuk memastikan, Anda jangan tahu bahwa (u)intX_tjenis yang opsional , kan?)
DevSolar

Jawaban:

69

Alasannya dijelaskan dalam makalah ini . Kutipan:

Ketika span diadopsi menjadi C ++ 17, itu menggunakan integer bertanda baik sebagai indeks dan ukuran. Sebagian ini untuk memungkinkan penggunaan "-1" sebagai nilai sentinel untuk menunjukkan jenis yang ukurannya tidak diketahui pada waktu kompilasi. Tetapi memiliki wadah STL yang fungsi size () mengembalikan nilai yang ditandatangani bermasalah, jadi P1089 diperkenalkan untuk "memperbaiki" masalah. Ini menerima dukungan mayoritas, tetapi bukan margin 2-ke-1 yang dibutuhkan untuk konsensus.

Makalah ini, P1227, adalah proposal untuk menambahkan fungsi non-member std :: ssize dan member ssize (). Dimasukkannya ini akan membuat kode tertentu jauh lebih mudah dan memungkinkan untuk menghindari unsigned-ness yang tidak diinginkan dalam perhitungan ukuran. Idenya adalah bahwa resistansi terhadap P1089 akan menurun jika ssize () tersedia untuk semua container, baik melalui std :: ssize () dan sebagai fungsi anggota.

Nadav Har'El
sumber
30
The for(int i = 0; i < container.ssize() - 1; ++i)contoh adalah juga cukup menarik
Caleth
7
@ John menurut saya memang mereka bisa melakukan hal yang sama seperti string :: npos dan hanya menggunakan size_t (-1) sebagai nilai khusus.
rubenvb
15
@ JohnZ.Li Sudah lama dianggap kesalahan bahwa jenis ukuran STL tidak ditandatangani. Sayangnya sekarang sudah terlambat untuk mereformasi itu. Menyediakan fungsi gratis adalah yang terbaik yang dapat kami lakukan saat ini.
LF
16
@LF: Itu adalah Herb Sutter dalam sebuah konferensi (mungkin Bjarne juga mengatakan ini). Tapi, dia sedikit salah. Sekarang, dengan komputer 32-bit / 64-bit, ukuran yang ditandatangani akan lebih baik (Jadi dia benar). Tetapi di masa lalu (ukuran 16-bit), ukuran yang ditandatangani akan menjadi buruk (misalnya, kita hanya dapat mengalokasikan array 32k byte).
geza
11
@LF: Saya menemukan Herb menyebutkan ini: youtube.com/watch?v=Puio5dly9N8&t=2667 . Ketika dia mengatakan bahwa "tidak banyak muncul dalam praktik", itu benar saat ini. Tapi itu tidak benar sama sekali> 20 tahun yang lalu (sistem 16-bit). Jadi, tidak terlalu salah jika menggunakan unsigned, saat STL dirancang.
geza
50

Dicuri secara serampangan dari Eric Niebler:

'Unsigned types signal that a negative index/size is not sane'adalah kebijaksanaan yang berlaku saat STL pertama kali dirancang. Tapi secara logis, hitungan hal tidak perlu positif. Saya mungkin ingin menyimpan hitungan dalam bilangan bulat bertanda untuk menunjukkan jumlah elemen yang ditambahkan atau dihapus dari koleksi. Kemudian saya ingin menggabungkannya dengan ukuran koleksinya. Jika ukuran koleksi tidak bertanda tangan, sekarang saya terpaksa mencampur aritmatika bertanda tangan dan tak bertanda tangan, yang merupakan bug farm. Penyusun memperingatkan tentang ini, tetapi karena desain STL cukup memaksa pemrogram ke dalam situasi ini, peringatan tersebut sangat umum sehingga kebanyakan orang mematikannya. Sayang sekali karena ini menyembunyikan bug yang nyata.

Penggunaan unsigned int di antarmuka bukanlah keuntungan yang dipikirkan banyak orang. Jika secara tidak sengaja pengguna memasukkan angka yang sedikit negatif ke API, tiba-tiba angka itu menjadi angka positif yang sangat besar. Seandainya API mengambil nomor sebagai yang ditandatangani, maka API dapat mendeteksi situasi dengan menyatakan bahwa nomor tersebut lebih besar dari atau sama dengan nol.

Jika kita membatasi penggunaan unsigned int menjadi bit twiddling (mis., Masks) dan menggunakan int bertanda tangan di tempat lain, bug cenderung tidak akan terjadi, dan lebih mudah dideteksi ketika memang terjadi.

sp2danny.danny
sumber
6
Swift mengambil pendekatan ini, meskipun tidak ada kekhawatiran tentang angka bertanda negatif yang ditafsirkan ulang sebagai angka besar yang tidak ditandatangani (karena tidak ada pemeran implisit, yang sebenarnya membuat Anda masuk ke rumah gila yang menyenangkan ini untuk memulai). Mereka hanya mengambil pendekatan (ukuran kata mesin) Intharus menjadi jenis mata uang umum dari bilangan bulat, bahkan di mana hanya bilangan positif yang masuk akal (seperti mengindeks array). Setiap penyimpangan dari itu harus beralasan. Sangat menyenangkan tidak perlu khawatir tentang pemeran di mana-mana.
Alexander - Kembalikan Monica
3
@ JohnZ.Li Memang, "unsigned int dianggap berbahaya untuk Java"
Nayuki