Mengapa ada begitu banyak kelas string di hadapan std :: string?

56

Sepertinya saya bahwa banyak perpustakaan C ++ yang lebih besar akhirnya menciptakan tipe string mereka sendiri. Dalam kode klien Anda juga harus menggunakan satu dari perpustakaan ( QString, CString, fbstringdll, saya yakin siapa pun dapat beberapa nama) atau tetap mengkonversi antara tipe standar dan satu penggunaan perpustakaan (yang sebagian besar waktu melibatkan setidaknya satu salinan).

Jadi, adakah kesalahan atau kekeliruan tertentu std::string(seperti auto_ptrsemantik yang buruk)? Apakah sudah diubah di C ++ 11?

Tamás Szelei
sumber
32
Ini disebut "sindrom Not Invented Here".
Cat Plus Plus
10
@CatPlusPlus QString dan CString keduanya telah dimiliki sebelumnya std :: string.
Gort the Robot
8
@Cat Plus Plus: Sindrom ini tampaknya tidak mempengaruhi kelas Java String.
Giorgio
20
@Giorgio: Pemrogram Java terlalu sibuk menciptakan solusi untuk kekurangan bahasa untuk khawatir tentang kelas string (Android reinvented String, by the way).
Cat Plus Plus
9
@Iorgio: Itu mungkin karena dukungan sintaksis hard-coded Java untuk java.lang.String(kurangnya overloading operator, dll) akan membuatnya sulit untuk menggunakan hal lain.
Mekanik siput

Jawaban:

57

Sebagian besar pustaka C ++ yang lebih besar telah dimulai sebelum std::stringdistandarisasi. Lainnya termasuk fitur tambahan yang terlambat standar, atau masih tidak standar, seperti dukungan untuk UTF-8 dan konversi antara pengkodean.

Jika perpustakaan itu diimplementasikan hari ini, mereka mungkin akan memilih untuk menulis fungsi dan iterator yang beroperasi pada std::stringinstance.

Ben Voigt
sumber
5
Dukungan untuk UTF-8 distandarisasi sejak C ++ 98. Dengan cara yang tidak nyaman dan sebagian implementasi yang didefinisikan sedemikian rupa sehingga hampir tidak ada yang bisa menggunakannya
AProgrammer
9
@AProgrammer: chardijamin cukup besar untuk menampung setiap codepoint UTF-8. AFAIK, itulah satu-satunya "dukungan" yang disediakan C ++ 98.
Ben Voigt
4
@AProgrammer: Dukungan itu benar-benar tidak berguna.
DeadMG
4
@AProgrammer lokal yang bisa dibilang rusak karena wchar_tini tidak cukup besar untuk mewakili semua kode poin Unicode. Selain itu, ada seluruh diskusi tentang UTF-16 yang dianggap berbahaya di mana argumen yang sangat meyakinkan dibuat bahwa UTF-8 harus digunakan secara eksklusif ...
Konrad Rudolph
6
@KonradRudolph, bukan sistem lokal yang rusak di sana (definisi wchar_t "cukup lebar untuk setiap rangkaian karakter yang didukung"); sistem yang memiliki komitmen terhadap 16 bit yang wchar_t lakukan pada saat yang sama berkomitmen untuk tidak mendukung Unicode. Nah, pelakunya adalah Unicode yang pertama kali dijamin bahwa ia tidak akan pernah menggunakan codepoint yang membutuhkan lebih dari 16 bit, kemudian sistem melakukan ke 16 bit wchar_t, kemudian beralih unicode membutuhkan lebih dari 16 bit.
Pemrogram
39

String adalah rasa malu besar C ++.

Untuk 15 tahun pertama Anda tidak menyediakan kelas string sama sekali - memaksa setiap kompiler pada setiap platform dan setiap pengguna untuk membuat sendiri.

Kemudian Anda membuat sesuatu yang bingung apakah itu seharusnya merupakan manipulasi string penuh API atau hanya wadah STL char, dengan beberapa algoritma yang menduplikasi yang ada di std :: Vector atau berbeda.

Di mana operasi string yang jelas seperti replace () atau mid () melibatkan kekacauan iterator sehingga Anda perlu memperkenalkan kata kunci 'otomatis' baru untuk menjaga pernyataan itu tetap pada satu halaman dan membuat kebanyakan orang menyerah pada seluruh bahasa .

Dan kemudian Anda memiliki unicode 'support' dan std :: wstring yang hanya arghh .....

<Bantuan> terima kasih - Saya merasa jauh lebih baik sekarang.

Martin Beckett
sumber
12
@DeadMG - ya dan telah distandarisasi pada tahun 1998, 15 tahun setelah ditemukan dan 6 tahun setelah MSFT menggunakannya. Ya iterator adalah cara yang berguna untuk membuat array dan daftar terlihat sama, apakah Anda pikir mereka adalah cara yang jelas untuk melakukan manipulasi string?
Martin Beckett
3
C with Classes ditemukan pada tahun 1983. Bukan C ++. Perpustakaan hanya Standar yang ditentukan oleh standar-mana, anehnya, hanya bisa terjadi setelah Anda memiliki Standard, sehingga mungkin tanggal awal untuk setiap perpustakaan standar adalah 1998. Dan iterator bisa dianggap persis sama untuk indeks, tapi sangat diketik. Saya mendukung fakta bahwa iterator mengisap dibandingkan dengan rentang, tapi itu tidak terlalu spesifik std::string. Kurangnya kelas String pada tahun 1983 tidak membenarkan memiliki lebih banyak dari mereka sekarang.
DeadMG
8
Saya pikir iostreams sangat memalukan C ++ ...
Doug T.
18
@DeadMG Orang-orang menggunakan sesuatu yang disebut "C ++" selama bertahun-tahun sebelum tahun 1998. Saya menulis program pertama saya menggunakan sesuatu yang disebut "C ++" pada tahun 1985. Jika Anda ingin mengatakan bahwa ini bukan "asli" C ++, itu tidak masalah, tetapi sebelum ini, kami menulis kode dan harus mendapatkan kelas string dari suatu tempat. Setelah kami memiliki basis kode warisan ini, kami tidak bisa benar-benar membuangnya atau menulis ulang dari awal ketika kami mendapatkan standar. Sekarang yang seharusnya terjadi adalah seharusnya ada kelas string yang datang dengan cfront.
Gort the Robot
8
@DeadMG - Jika tidak ada yang menggunakan bahasa sampai memiliki sertifikat ISO maka tidak ada bahasa yang akan digunakan karena tidak akan pernah sampai ke ISO. Tidak ada standar ISO untuk assembler x86 tapi saya senang menggunakan platform
Martin Beckett
32

Sebenarnya ... ada beberapa masalah dengan std::string, dan ya itu menjadi sedikit lebih baik di C ++ 11, tapi jangan maju dulu.

QStringdan CStringmerupakan bagian dari pustaka lama , oleh karena itu pustaka ada sebelum C ++ distandarisasi (seperti SGI STL). Karena itu mereka harus membuat kelas.

fbstringmengatasi masalah kinerja yang sangat spesifik. Standar ini menetapkan antarmuka dan kompleksitas algoritmik yang menjamin minima, namun Standar Kualitas Implementasi merinci apakah ini cepat atau tidak. fbstringmemiliki pengoptimalan spesifik (terkait penyimpanan, atau lebih cepat findmisalnya).

Kekhawatiran lain yang tidak ditimbulkan di sini (en vrac):

  • di C ++ 03 tidak wajib bahwa penyimpanan berdekatan, membuat interoperabilitas dengan C berpotensi sulit. C ++ 11 memperbaiki ini.
  • std::string adalah pengkodean yang tidak disadari, dan tidak memiliki kode khusus untuk UTF-8, mudah untuk menyimpan string UTF-8 di dalamnya dan merusaknya secara tidak sengaja
  • std::stringantarmuka membengkak , banyak metode bisa diimplementasikan sebagai fungsi bebas dan banyak yang digandakan agar sesuai dengan antarmuka berbasis indeks dan antarmuka berbasis iterator.
Matthieu M.
sumber
5
Perhatian # 1 - C ++ 03 21.3.6 / 1 menjamin bahwa c_str()mengembalikan sebuah pointer ke penyimpanan yang berdekatan, yang menyediakan beberapa interoperabilitas C. Namun Anda tidak dapat mengubah data yang diarahkan ke. Penanganan yang umum termasuk menggunakan a vector<char>.
John Dibling
@JohnDibling: Ya, dan ada batasan lain: itu bisa menimbulkan salinan dalam penyimpanan yang baru dialokasikan (Standar tidak mengatakan itu tidak boleh). Tentu saja C ++ 11 tidak mencegah penyalinan, tetapi karena Anda dapat melakukannya &s[0], tidak masalah lagi :)
Matthieu M.
1
@ MatthieuM .: Pointer yang diperoleh via &s[0]mungkin tidak menunjuk ke string yang diakhiri NUL (kecuali c_str()telah dipanggil sejak modifikasi terakhir).
Ben Voigt
2
@Matthieu: Buffer lain tidak diizinkan. " c_str()Pengembalian: Sebuah penunjuk psedemikian rupa sehingga p + i == &operator[](i)untuk masing - masing idalam [0,size()]"
Ben Voigt
3
Yang juga perlu dicatat adalah bahwa tidak ada orang waras yang menggunakan MFC lagi, jadi sulit untuk berargumen bahwa CString adalah kelas string dalam C ++ modern.
DeadMG
7

Terlepas dari alasan yang diposting di sini ada juga satu lagi - kompatibilitas biner . Penulis perpustakaan tidak memiliki kendali atas std::stringimplementasi yang Anda gunakan dan apakah memiliki tata letak memori yang sama dengan mereka.

std::stringadalah templat, jadi implementasinya diambil dari tajuk STL lokal Anda. Sekarang bayangkan Anda secara lokal menggunakan beberapa versi STL yang dioptimalkan kinerja, sepenuhnya kompatibel dengan standar. Misalnya, Anda mungkin telah memilih untuk mengganggu buffer statis di masing std::string- masing untuk mengurangi jumlah alokasi dinamis dan kesalahan cache. Akibatnya, tata letak memori dan / atau ukuran implementasi Anda berbeda dari yang perpustakaan.

Jika hanya tata letak yang berbeda, beberapa std::stringfungsi anggota memanggil instance yang dikirimkan dari pustaka ke klien atau sebaliknya mungkin gagal, bergantung pada anggota yang dipindahkan.

Jika ukurannya juga berbeda, semua tipe perpustakaan yang memiliki std::stringanggota akan tampak memiliki ukuran yang berbeda ketika diperiksa di perpustakaan dan dalam kode klien. Anggota data yang mengikuti std::stringanggota akan memiliki perubahan offset juga, dan akses langsung / aksesor inline yang dipanggil dari klien akan mengembalikan sampah, meskipun "tampak OK" ketika men-debug perpustakaan itu sendiri.

Bottomline - jika pustaka dan kode klien dikompilasi terhadap std::stringversi yang berbeda , mereka akan terhubung dengan baik, tetapi mungkin menghasilkan beberapa bug yang sulit dimengerti. Jika Anda mengubah std::stringimplementasi Anda, semua perpustakaan yang mengekspos anggota dari STL harus dikompilasi ulang agar sesuai dengan std::stringtata letak klien . Dan karena pemrogram ingin perpustakaan mereka menjadi kuat, Anda jarang melihat di std::stringmana saja.

Agar adil, ini berlaku untuk semua jenis STL. IIRC mereka tidak memiliki tata letak memori yang standar.

gwiazdorrr
sumber
2
Anda harus menjadi seorang programmer * nix. Kompatibilitas biner C ++ tidak sama pada semua platform, dan khususnya pada Windows NO kelas yang berisi data anggota bersifat portable di antara kompiler.
Ben Voigt
(Maksud saya kecuali jenis POD, dan bahkan kemudian persyaratan pengemasan eksplisit diperlukan)
Ben Voigt
1
Terima kasih atas masukan, walaupun saya tidak berbicara kompiler yang berbeda, saya berbicara STL berbeda.
gwiazdorrr
1
+1: ABI adalah alasan besar untuk menggulung versi Anda sendiri dari kelas yang disediakan kompiler. Untuk itu saja, saya berharap ini adalah jawaban yang diterima.
Thomas Eding
6

Ada banyak jawaban untuk pertanyaan ini tetapi ada beberapa:

  1. Warisan. Banyak perpustakaan dan kelas string ditulis SEBELUMNYA dengan keberadaan std :: string.

  2. Untuk kompatibilitas dengan kode dalam C. Library std :: string adalah C ++ di mana ada perpustakaan string lain yang bekerja dengan C dan C ++.

  3. Untuk menghindari alokasi dinamis. Pustaka std :: string menggunakan alokasi dinamis dan mungkin tidak cocok untuk sistem tertanam, interupsi atau kode terkait waktu nyata, atau untuk fungsionalitas tingkat rendah.

  4. Templat. Pustaka std :: string didasarkan pada templat. Sampai cukup baru-baru ini sejumlah kompiler C ++ memiliki dukungan template yang berkinerja buruk atau bahkan bermasalah. Sayangnya, saya bekerja di sebuah industri yang menggunakan banyak alat khusus dan salah satu dari rantai alat kami dari pemain utama di industri ini tidak "secara resmi" 100% mendukung C ++ (dengan barang buggy menjadi templat et al).

Mungkin ada banyak alasan yang lebih valid juga.

Adisak
sumber
2
"Cukup baru-baru ini" yang berarti "Sudah satu dekade sejak bahkan Visual Studio memiliki dukungan yang cukup masuk akal untuk mereka"?
DeadMG
@DeadMG - Visual Studio bukan satu-satunya kompiler yang tidak patuh di dunia. Saya bekerja di permainan video dan kami sering mengerjakan kompiler khusus untuk platform perangkat keras yang tidak dirilis (terjadi setiap beberapa tahun dalam siklus konsol atau saat perangkat keras baru muncul). "Cukup baru-baru ini" berarti hari ini - Saat ini beberapa kompiler tidak mendukung templat dengan baik. Saya tidak bisa spesifik tanpa melanggar NDA, tetapi saya saat ini bekerja pada platform dengan custom toolchains di mana dukungan C ++ - terutama kepatuhan template - dianggap "eksperimental".
Adisak
4

Sebagian besar tentang Unicode. Dukungan Standar untuk Unicode buruk sekali, dan semua orang memiliki kebutuhan Unicode mereka sendiri. Sebagai contoh, ICU mendukung setiap fungsi Unicode yang Anda inginkan, di balik antarmuka Java-dihasilkan-dari-Jawa yang paling menjijikkan yang mungkin Anda bayangkan, dan jika Anda berada di Unix terjebak dengan UTF-16 mungkin bukan ide Anda tentang waktu yang baik.

Selain itu, banyak orang memerlukan tingkat dukungan Unicode yang berbeda-tidak semua orang membutuhkan API tata letak teks yang rumit dan hal-hal semacam itu. Jadi, mudah untuk melihat mengapa ada banyak kelas string - yang standar cukup payah dan semua orang memiliki kebutuhan yang berbeda dari yang baru, dengan tidak ada yang mengelola untuk membuat kelas tunggal yang dapat melakukan banyak dukungan lintas platform Unicode dengan antarmuka yang menyenangkan.

Menurut pendapat saya, ini sebagian besar kesalahan Komite C ++ karena tidak benar memberikan dukungan untuk Unicode- pada tahun 1998 atau 2003, mungkin itu bisa dimengerti, tetapi tidak di C ++ 11. Semoga di C ++ 17 mereka akan melakukan yang lebih baik.

DeadMG
sumber
Halo, C ++ 20 di sini, coba tebak apa yang terjadi pada dukungan Unicode?
Passer By
-4

Itu karena setiap programmer memiliki sesuatu untuk dibuktikan dan merasakan kebutuhan untuk membuat kelas string mereka sendiri yang luar biasa, lebih cepat untuk fungsi mereka yang luar biasa. Biasanya sedikit berlebihan dan mengarah ke semua jenis konversi string ekstra dalam pengalaman saya.

Chad Stewart
sumber
7
Apakah ini benar, saya berharap untuk melihat sejumlah implementasi String yang serupa dalam bahasa seperti Java di mana implementasi yang baik telah tersedia selama ini.
Bill K
@ Bill Java String adalah final, jadi Anda harus meletakkan fungsi baru di tempat lain.
Dan maksud saya adalah, bahkan final, dalam 20 tahun saya belum pernah melihat orang menulis implementasi string kustom (Ya, saya memang berusaha untuk meningkatkan kinerja penggabungan string tetapi ternyata java JAUH lebih pintar di string + string daripada Anda ' d bayangkan)
Bill K
2
@ Bill: Itu mungkin ada hubungannya dengan budaya yang berbeda. C ++ menarik mereka yang ingin memahami detail level rendah. Java menarik mereka yang hanya ingin menyelesaikan pekerjaan menggunakan blok bangunan orang lain. (Perhatikan bahwa ini bukan pernyataan tentang individu tertentu yang memilih untuk menggunakan bahasa mana pun, tetapi tentang tujuan dan budaya desain masing-masing bahasa)
Ben Voigt