Praktik terburuk dalam C ++, kesalahan umum [ditutup]


35

Setelah membaca kata-kata kasar yang terkenal dari Linus Torvalds ini , saya bertanya-tanya apa sebenarnya yang menjadi perangkap bagi para programmer di C ++. Saya secara eksplisit tidak merujuk pada kesalahan ketik atau aliran program yang buruk sebagaimana diperlakukan dalam pertanyaan ini dan jawabannya , tetapi untuk lebih banyak kesalahan tingkat tinggi yang tidak terdeteksi oleh kompiler dan tidak menghasilkan bug yang jelas pada saat pertama kali dijalankan, menyelesaikan kesalahan desain, hal-hal yang tidak mungkin dalam C tetapi cenderung dilakukan dalam C ++ oleh pendatang baru yang tidak memahami implikasi penuh dari kode mereka.

Saya juga menyambut jawaban yang menunjukkan penurunan kinerja yang sangat besar yang biasanya tidak diharapkan. Sebuah contoh dari apa yang pernah dikatakan salah seorang profesor saya tentang generator pengurai LR (1) yang saya tulis:

Anda telah menggunakan terlalu banyak contoh pewarisan dan keutamaan yang tidak dibutuhkan. Warisan membuat desain jauh lebih rumit (dan tidak efisien karena subsistem RTTI (run-time type inference)), dan oleh karena itu hanya boleh digunakan jika masuk akal, misalnya untuk tindakan dalam tabel parse. Karena Anda menggunakan templat secara intensif, praktis Anda tidak memerlukan pewarisan. "


6
Beberapa kesalahan yang lebih buruk yang dapat Anda lakukan di C / C ++ sebagian besar karena warisan C ... membaca perilaku yang tidak terdefinisi, manajemen memori manual, dll. Juga, saran prof tampaknya palsu / salah (bagi saya, yang tidak ahli C ++) - contoh instantiasi harus menghasilkan kelas normal dengan vtable untuk virtualfungsi, kan?

8
Anda salah mengingat apa yang dikatakan profesor Anda, atau dia tidak tahu apa yang sedang dibicarakannya. Kelas turunan umumnya tidak perlu menggunakan RTTI (refleksi AKA) untuk mencari sesuatu. Jika mereka menggunakan metode virtual, kode mungkin perlu melakukan pencarian vtable untuk pengiriman, tetapi itu diterjemahkan menjadi instruksi ASM tunggal pada banyak prosesor. Karena masalah caching dapat memperlambat segalanya dengan jumlah tertentu, tetapi Anda tidak akan pernah melihat overhead dalam kasus penggunaan apa pun kecuali yang paling menuntut. Ada banyak alasan bagus untuk menghindari C ++, tetapi pencarian vtable bukan salah satunya.
Mason Wheeler

5
@FelixDombek: Dinyatakan secara umum dan diterapkan di seluruh papan, kutipan dari profesor Anda itu hanya menunjukkan sejumlah besar ketidaktahuan. Ketika desain Anda membutuhkan polimorfisme runtime dari beberapa jenis, menggunakan fungsi virtual sering merupakan pilihan terbaik; ketika Anda tidak membutuhkannya, jangan gunakan itu: Anda tidak perlu semua metode menjadi virtual hanya karena Anda menggunakan kelas turunan, misalnya.
Fred Nurk

5
@Mason Wheeler: RTTI berisi informasi tentang jenisnya, cukup untuk dapat menentukan apakah a dynamic_castharus berhasil atau tidak, dan beberapa hal lain, tetapi refleksi mencakup lebih banyak lagi, termasuk kemampuan untuk mengambil informasi tentang atribut atau fungsi anggota, yang tidak hadir dalam C ++.
David Rodríguez - dribeas

5
Komentar profesor agak menipu, karena fungsi pewarisan dan virtual bukanlah hit kinerja besar. Nasihat untuk menggunakan pewarisan sangat sedikit, tetapi lebih merupakan masalah struktur program daripada efisiensi. Warisan, terutama dengan anggota yang dilindungi, adalah tentang sedekat kopling yang akan Anda dapatkan, dan jika Anda tidak membutuhkannya Anda tidak harus menggunakannya.
David Thornley

Jawaban:


69

Torvalds sedang berbicara dari pantatnya di sini.


OK, mengapa dia berbicara di luar pantatnya:

Pertama-tama, kata-kata kasarnya sebenarnya bukan kata-kata kasar. Ada sangat sedikit konten aktual di sini. Satu-satunya alasan itu benar-benar terkenal atau bahkan sedikit dihormati adalah karena dibuat oleh Dewa Linux. Argumen utamanya adalah bahwa C ++ adalah omong kosong dan dia suka mengencingi orang C ++. Tentu saja tidak ada alasan sama sekali untuk menanggapi hal itu dan siapa pun yang menganggapnya sebagai argumen yang masuk akal adalah di luar pembicaraan.

Mengenai apa yang mungkin disorot sebagai poinnya yang paling objektif:

  • STL dan Boost adalah omong kosong <- terserah. Anda idiot.
  • STL dan Boost menyebabkan rasa sakit yang tak terhingga <- konyol. Jelas dia sengaja berlebihan tapi kemudian apa pernyataan sebenarnya di sini? Saya tidak tahu Ada beberapa yang lebih sulit untuk mencari tahu masalah ketika Anda menyebabkan muntah compiler di Spirit atau sesuatu, tetapi tidak lebih atau kurang sulit untuk mencari tahu daripada debugging UB yang disebabkan oleh penyalahgunaan konstruksi C seperti void *.
  • Model abstrak yang didorong oleh C ++ tidak efisien. <- Seperti apa? Dia tidak pernah mengembang, tidak pernah memberikan contoh apa pun dari apa yang dia maksud, dia hanya mengatakannya. BFD. Karena saya tidak tahu apa yang dia maksudkan, tidak ada gunanya mencoba "menolak" pernyataan itu. Ini adalah mantra umum dari C fanatik tetapi itu tidak membuatnya lebih dimengerti atau dimengerti.
  • Penggunaan C ++ yang benar berarti Anda membatasi diri Anda pada aspek C. <- Sebenarnya kode WORSE C ++ di luar sana melakukan ini, jadi saya masih belum tahu WTF yang dia bicarakan.

Pada dasarnya, Torvalds berbicara keluar dari pantatnya. Tidak ada argumen yang masuk akal tentang apa pun. Mengharapkan bantahan serius atas omong kosong semacam itu benar-benar konyol. Saya diberitahu untuk "memperluas" pada sanggahan atas sesuatu yang saya harapkan untuk diperluas jika itu di mana saya yang mengatakannya. Jika Anda benar-benar, dengan jujur ​​melihat apa yang dikatakan Torvalds, Anda akan melihat bahwa dia tidak benar-benar mengatakan apa-apa.

Hanya karena Tuhan berkata itu tidak berarti itu masuk akal atau harus dianggap lebih serius daripada jika beberapa bozo acak mengatakannya. Sejujurnya, Tuhan hanyalah bozo acak.


Menanggapi pertanyaan aktual:

Mungkin yang terburuk, dan paling umum, praktik C ++ buruk adalah memperlakukannya seperti C. Terus menggunakan fungsi C API seperti printf, mendapat (juga dianggap buruk dalam C), strtok, dll ... tidak hanya gagal memanfaatkan daya yang disediakan oleh sistem tipe yang lebih ketat, mereka pasti mengarah pada komplikasi lebih lanjut ketika mencoba berinteraksi dengan kode C ++ "asli". Jadi pada dasarnya, lakukan kebalikan dari apa yang disarankan oleh Torvalds.

Pelajari cara memanfaatkan STL dan Boost untuk mendapatkan lebih lanjut waktu kompilasi deteksi bug dan untuk membuat hidup Anda lebih mudah dengan cara lain yang umum (dorongan tokenizer misalnya adalah tipe aman DAN antarmuka yang lebih baik). Memang benar bahwa Anda harus belajar cara membaca kesalahan template, yang pada awalnya menakutkan, tetapi (menurut pengalaman saya), sebenarnya jauh lebih mudah daripada mencoba men-debug sesuatu yang menghasilkan perilaku tidak terdefinisi selama runtime, yang dibuat oleh C api cukup mudah dilakukan.

Bukan untuk mengatakan bahwa C tidak sebaik. Saya tentu saja suka C ++ lebih baik. Pemrogram C menyukai C lebih baik. Ada trade off dan suka subjektif yang dimainkan. Ada juga banyak informasi yang salah dan FUD beredar. Saya akan mengatakan bahwa ada lebih banyak FUD dan kesalahan informasi yang beredar tentang C ++ tapi saya bias dalam hal ini. Sebagai contoh, masalah "mengasapi" dan "kinerja" yang seharusnya dimiliki C ++ sebenarnya bukan masalah utama sebagian besar waktu dan tentu saja meledak dari proporsi realitas.

Mengenai masalah yang dirujuk oleh profesor Anda, ini tidak unik untuk C ++. Dalam OOP (dan dalam pemrograman generik) Anda ingin memilih komposisi daripada warisan. Warisan adalah hubungan penggabungan sekuat mungkin yang ada dalam semua bahasa OO. C ++ menambahkan satu lagi yang lebih kuat, persahabatan. Warisan polimorfik harus digunakan untuk mewakili abstraksi dan hubungan "is-a", itu tidak boleh digunakan untuk digunakan kembali. Ini adalah kesalahan terbesar kedua yang dapat Anda lakukan di C ++, dan ini adalah kesalahan yang cukup besar, tetapi jauh dari keunikan bahasa. Anda dapat membuat hubungan warisan yang terlalu kompleks di C # atau Java juga, dan mereka akan memiliki masalah yang sama persis.


1
Ironis, hingga 2007, git hanya menjalankan Linux versi portable. Ya, sistem apa pun yang mirip. Kemudian lagi, mengingat keadaan yang mengarah pada penciptaan git, aku tentu saja tidak menentangnya.
Chris K

9
Linus kesulitan menemukan programmer C ++ yang baik yang ingin bekerja untuknya. Bertanya-tanya mengapa? Saya pikir ini hanya masalah ayam dan telur.
Bo Persson

19

Saya selalu berpikir bahwa bahaya C ++ sangat dibesar-besarkan oleh programmer C yang tidak berpengalaman.

Ya, C ++ lebih sulit untuk diambil daripada Java, tetapi jika Anda memprogram menggunakan teknik modern, cukup mudah untuk menulis program yang kuat. Sejujurnya saya tidak memiliki waktu pemrograman yang lebih sulit dalam C ++ daripada yang saya lakukan dalam bahasa seperti Java, dan saya sering mendapati diri saya kehilangan abstraksi C ++ tertentu seperti templat dan RAII ketika saya mendesain dalam bahasa lain.

Yang mengatakan, bahkan setelah bertahun-tahun pemrograman dalam C ++, setiap sekarang dan kemudian saya akan membuat kesalahan yang sangat bodoh yang tidak mungkin dilakukan dalam bahasa tingkat yang lebih tinggi. Salah satu perangkap umum di C ++ mengabaikan umur objek: di Jawa dan C # Anda biasanya tidak perlu peduli dengan objek seumur hidup *, karena semua objek ada di heap dan mereka dikelola untuk Anda oleh pengumpul sampah ajaib.

Sekarang, dalam C ++ modern, biasanya Anda tidak perlu terlalu peduli tentang objek seumur hidup. Anda memiliki destruktor dan pointer cerdas yang mengatur masa pakai objek untuk Anda. 99% dari waktu, ini bekerja dengan sangat baik. Tetapi setiap sekarang dan nanti, Anda akan mendapatkan kacau oleh pointer menggantung (atau referensi.) Misalnya, baru-baru ini saya punya objek (sebut saja Foo) yang berisi variabel referensi internal ke objek lain (sebut saja Bar). Pada satu titik, saya dengan bodoh mengatur hal-hal sehingga Barkeluar dari ruang lingkup sebelumnya Foo, namun Foodestructor akhirnya memanggil fungsi anggota Bar. Tak perlu dikatakan, semuanya tidak berjalan dengan baik.

Sekarang, saya tidak bisa menyalahkan C ++ untuk ini. Itu desain buruk saya sendiri, tetapi intinya adalah hal seperti ini tidak akan terjadi dalam bahasa tingkat tinggi yang dikelola. Bahkan dengan pointer cerdas dan sejenisnya, Anda kadang-kadang masih perlu memiliki kesadaran objek seumur hidup.


* Jika sumber daya yang dikelola adalah memori, itu adalah.


8
Tidak pernah benar-benar harus peduli tentang objek seumur hidup di Jawa dan C #? GC mereka mengatur memori, tetapi itu hanya sebagian kecil dari RAII bagi saya; lihat berbagai "pakai" antarmuka bahasa yang dimiliki, misalnya.
Fred Nurk

Harus peduli dengan objek seumur hidup akan jarang terjadi di Jawa kecuali untuk desain perpustakaan I / O yang tidak nyaman.
dan04

Masalah referensi menggantung Anda adalah sesuatu yang saya tertarik untuk coba pecahkan. Saya memulai diskusi di blog saya tentang arah yang saya tuju untuk menyelesaikannya (janji penunjuk). Pada dasarnya saya pikir bahasanya bisa menggunakan beberapa pointer cerdas. Ambil bagian dalam diskusi itu jika Anda tertarik. Tidak ada orang lain yang melakukan apa pun ... tetapi jika itu sesuatu yang ingin Anda selesaikan ... saya benar-benar mengalami lebih dari 10% masalah.
Edward Strange

13

Perbedaan dalam kode biasanya lebih terkait dengan programmer daripada bahasa. Secara khusus, seorang programmer C ++ yang baik dan seorang programmer C akan mendapatkan solusi yang sama baiknya (walaupun berbeda). Sekarang, C adalah bahasa yang lebih sederhana (sebagai bahasa) dan itu berarti bahwa ada lebih sedikit abstraksi dan lebih banyak visibilitas ke dalam apa kode sebenarnya.

Sebagian dari kata-kata kasarnya (ia dikenal karena kata-katanya kasar terhadap C ++) didasarkan pada kenyataan bahwa lebih banyak orang akan menggunakan C ++, dan menulis kode tanpa benar-benar memahami apa yang disembunyikan oleh beberapa abstraksi dan membuat asumsi yang salah.


3
Berapa biaya iterasi dari std::vector<bool>perubahan setiap nilai? for ( std::vector<bool>::iterator it = v.begin(), end = v.end(); it != end; ++it ) { *it = !*it; }? Apa yang disarikan dalam *it = !*it;?
David Rodríguez - dribeas

2
Meskipun mungkin tidak adil untuk memilih kekejian bahasa tertentu yang secara luas dikritik sebagai kesalahan ...
Fred Nurk

2
@Fred Nurk: std::vector<bool>adalah kesalahan yang sudah diketahui, tetapi itu adalah contoh yang sangat bagus dari apa yang sedang dibahas: abstraksi itu bagus, tetapi Anda harus berhati-hati dengan apa yang mereka sembunyikan. Hal yang sama dapat dan akan terjadi dalam kode pengguna. Sebagai permulaan, saya telah melihat baik di C ++ dan orang Jawa menggunakan pengecualian untuk melakukan kontrol aliran, dan kode yang terlihat seperti panggilan fungsi bersarang yang sebenarnya merupakan peluncur pengecualian bailout: void endOperation();diimplementasikan sebagai throw EndOperation;. Seorang programmer yang baik akan menghindari konstruksi mengejutkan itu , tetapi kenyataannya adalah Anda dapat menemukannya.
David Rodríguez - dribeas

5
Salah satu poin dari Torvalds adalah bahwa: ia dapat mengusir pemula hanya dengan memilih C lebih dari C ++ (tampaknya ada lebih banyak C ++ pemula) dan C ++ menjadi lebih kompleks memiliki kurva belajar yang lebih curam dan ada lebih banyak kemungkinan tersandung di sudut kasus .
David Rodríguez - dribeas

2
+1, inilah yang dikeluhkan Linus. Dia dianggap anti-C ++, tapi itu tidak terlalu. Dia hanya anti-C ++ - programmer.
greyfade

13

Terlalu sering menggunakan try/catchblok.

File file("some.txt");
try
{
  /**/

  file.close();
}
catch(std::exception const& e)
{
  file.close();
}

Ini biasanya berasal dari bahasa seperti Java dan orang-orang akan berpendapat bahwa C ++ tidak memiliki finalizeklausa.

Tetapi kode ini menunjukkan dua masalah:

  • Anda harus membuat filesebelum try/catch, karena Anda tidak dapat benar close- benar file yang tidak ada di catch. Ini mengarah pada "ruang lingkup kebocoran" yang fileterlihat setelah ditutup. Anda dapat menambahkan satu blok tetapi ...: /
  • Jika seseorang datang dan menambahkan returndi tengah-tengah tryruang lingkup, maka file tidak ditutup (itulah sebabnya orang mengeluh tentang kurangnya finalizeklausa)

Namun, dalam C ++, kami memiliki cara yang jauh lebih efisien untuk menangani masalah ini yang:

  • Jawa finalize
  • C # using
  • Pergi defer

Kami memiliki RAII, yang propertinya benar-benar menarik disimpulkan sebagai terbaik SBRM(Manajemen Sumber Daya Terikat Scoped Bound).

Dengan membuat kelas sehingga destruktornya membersihkan sumber daya yang dimilikinya, kami tidak menempatkan tanggung jawab mengelola sumber daya pada setiap dan setiap penggunanya!

Ini adalah yang fitur aku rindu dalam bahasa lain, dan mungkin salah satu yang paling terlupakan.

Yang benar adalah bahwa jarang ada kebutuhan bahkan untuk menulis try/catchblok di C ++, terpisah di tingkat atas untuk menghindari penghentian tanpa login.


1
Saya tidak berpikir itu pengaruh Jawa sebanyak itu C. (Anda bisa langsung mengganti fopendan di fclosesini.) RAII adalah cara yang "tepat" untuk melakukan hal-hal di sini, tapi itu tidak nyaman bagi orang-orang yang ingin menggunakan perpustakaan C dari C ++ .
dan04

Untuk jenis jawaban ini, memberikan contoh solusi yang tepat, akan sesuai.
Claus Jørgensen

@ ClausJørgensen: Ya, solusinya sayangnya tidak benar-benar "mencolok" karena hanya melibatkan File file("some.txt");dan itu saja (tidak open, tidak close, tidak try...)
Matthieu M.

D juga memiliki RAII
Demi

@ Demetri: Saya tidak terlalu terbiasa dengan D, bisakah Anda menjelaskan bagaimana RAII berinteraksi dengan Pengumpulan Sampah? Saya tahu bahwa dengan Python Anda dapat menulis metode "deinit", namun dokumentasi memperingatkan bahwa dalam kasus siklus referensi beberapa objek tidak akan melihat metode deinit mereka dipanggil.
Matthieu M.

9

Satu kesalahan umum yang sesuai dengan kriteria Anda adalah tidak memahami bagaimana copy constructor bekerja ketika berhadapan dengan memori yang dialokasikan di kelas Anda. Saya telah kehilangan hitungan waktu yang saya habiskan untuk memperbaiki crash atau kebocoran memori karena 'noob' memasukkan objek mereka ke peta atau vektor dan tidak menulis copy constructor dan destructor dengan benar.

Sayangnya C ++ penuh dengan gotcha 'tersembunyi' seperti ini. Tetapi mengeluh tentang itu seperti mengeluh Anda pergi ke Prancis dan tidak bisa mengerti apa yang orang katakan. Jika Anda akan pergi ke sana, pelajari bahasanya.


1
Saya pikir masalah dengan C ++ adalah sangat mudah menembak diri sendiri di kaki. Tentu, ada programmer C ++ yang bagus, banyak software bagus yang ditulis dalam C ++. Tetapi sangat sulit untuk menjadi pengembang C ++ yang baik. Seri Scott Meyers 'Efficient C ++' menunjukkan berapa banyak kehalusan bahasa.
Marco Mustapic

Saya setuju. Bagian dari masalah adalah bahwa banyak (mayoritas) programmer C ++ berpikir mereka tahu apa yang mereka lakukan ketika mereka jelas tidak melakukannya. Apakah maksud Anda "Efektif C ++"?
Henry

Setidaknya ini menjadi lebih baik dengan aturan baru yang agak membatasi pada operasi implisit copy / move di C ++ 0x. Dalam banyak kasus pelanggaran aturan, generasi operasi copy yang tersirat akan ditinggalkan dan harus menghasilkan peringatan.
sellibitze

6

C ++ memungkinkan berbagai macam fitur dan gaya pemrograman, tetapi itu tidak berarti ini sebenarnya cara yang baik untuk C ++ untuk digunakan. Dan nyatanya, sangat mudah menggunakan C ++ secara tidak benar.

Itu harus dipelajari dan dipahami dengan benar , hanya belajar dengan melakukan (atau menggunakannya seperti orang akan menggunakan bahasa lain) akan menyebabkan kode tidak efisien dan rawan kesalahan.


4

Baiklah ... Sebagai permulaan Anda dapat membaca C ++ FAQ Lite

Kemudian, beberapa orang membangun karier menulis buku tentang seluk-beluk C ++:

Herb Sutter dan Scott Meyers .

Adapun kata-kata kasar Torvalds yang kurang substansi ... datang pada orang-orang, serius: Tidak ada bahasa lain di luar sana yang memiliki begitu banyak tinta tumpah karena berurusan dengan nuansa bahasa. Buku Python & Ruby & Java Anda semua fokus pada aplikasi penulisan ... Buku C ++ Anda berfokus pada fitur / tip / perangkap bahasa yang konyol.


1
Hmm ... javapuzzlers.com , jimbrooks.org/web/python/#Pitfalls . Aku akan mengatakan Accelerated C ++ (untuk salah satu contoh) berfokus banyak lebih tentang cara menulis kode dari pada mereka ini ...
Jerry Coffin

1
Anda telah membawa beberapa contoh sumber daya yang menunjukkan kasus tepi dalam bahasa masing-masing; hal-hal yang terlihat aneh dan Anda tidak yakin bagaimana cara kerjanya (walaupun hal-hal daftar python sudah dekat) ... C ++ memiliki seluruh industri yang menunjukkan hal-hal yang terlihat benar-benar valid yang berperilaku dengan cara yang tidak Anda harapkan.
red-dirt

3

Templating yang terlalu berat mungkin tidak menghasilkan bug pada awalnya. Namun seiring berjalannya waktu, orang perlu mengubah kode itu, dan mereka akan kesulitan memahami templat yang sangat besar. Saat itulah bug masuk - kesalahpahaman menyebabkan "It mengkompilasi dan menjalankan" komentar, yang sering menyebabkan kode hampir-tetapi-tidak-cukup-benar.

Secara umum jika saya melihat diri saya melakukan templat generik dalam tiga tingkat, saya berhenti dan berpikir bagaimana itu bisa direduksi menjadi satu. Seringkali masalah diselesaikan dengan mengekstraksi fungsi atau kelas.


8
Mempertahankan kode yang rumit dalam menghadapi perubahan persyaratan selalu menyebabkan bug tanpa banyak usaha, tidak ada yang khusus tentang template di sana.
Fred Nurk

2

Peringatan: ini hampir tidak sebanyak jawaban sebagai kritik terhadap pembicaraan yang "dikaitkan pengguna" dalam jawaban.

Poin utama pertamanya adalah (seharusnya) "standar yang terus berubah". Pada kenyataannya, contoh-contoh yang ia berikan berhubungan dengan perubahan C ++ sebelum ada standar. Sejak tahun 1998 (ketika standar C ++ pertama selesai) perubahan bahasa sudah sangat minim - pada kenyataannya, banyak yang akan berpendapat bahwa masalah sebenarnya adalah bahwa lebih banyak perubahan harus dibuat. Saya cukup yakin bahwa semua kode yang sesuai dengan standar C ++ asli masih sesuai dengan standar saat ini. Meskipun agak kurang pasti, kecuali jika sesuatu berubah dengan cepat (dan sangat tidak terduga), hal yang sama akan benar dengan standar C ++ yang akan datang juga (secara teoritis, semua kode yang digunakanexportakan pecah, tetapi hampir tidak ada; dari sudut pandang praktis, ini bukan masalah). Saya dapat memikirkan beberapa bahasa lain, OS (atau banyak hal lain yang berhubungan dengan komputer) yang dapat membuat klaim semacam itu.

Dia kemudian masuk ke "gaya yang selalu berubah". Sekali lagi, sebagian besar poinnya cukup dekat dengan omong kosong. Dia mencoba untuk menggambarkan for (int i=0; i<n;i++)sebagai "tua dan rusak" dan for (int i(0); i!=n;++i)"panas baru". Kenyataannya adalah bahwa walaupun ada beberapa tipe yang perubahannya masuk akal, karena int, tidak ada bedanya - dan bahkan ketika Anda bisa mendapatkan sesuatu, jarang diperlukan untuk menulis kode yang baik atau benar. Bahkan yang terbaik, dia membuat gunung dari molehill.

Klaim berikutnya adalah bahwa C ++ adalah "mengoptimalkan ke arah yang salah" - khususnya, bahwa meskipun ia mengakui bahwa menggunakan perpustakaan yang baik itu mudah, ia mengklaim bahwa C ++ "membuat penulisan perpustakaan yang baik hampir mustahil." Di sini, saya percaya adalah salah satu kesalahannya yang paling mendasar. Pada kenyataannya, menulis perpustakaan yang bagus untuk hampir semua bahasa sangat sulit. Paling tidak, menulis perpustakaan yang baik membutuhkan pemahaman beberapa domain masalah dengan baik sehingga kode Anda berfungsi untuk banyak aplikasi yang mungkin di (atau terkait dengan) domain itu. Sebagian besar dari apa yang dilakukan C ++ sebenarnya adalah "menaikkan standar" - setelah melihat seberapa baik perpustakaan dapat , orang jarang mau kembali menulis jenis ombak yang seharusnya mereka miliki.coders yang benar - benar baik menulis beberapa perpustakaan, yang kemudian dapat digunakan (dengan mudah, seperti yang dia akui) oleh "kita semua". Ini benar-benar kasus di mana "itu bukan bug, itu fitur."

Saya tidak akan mencoba untuk mencapai setiap titik secara berurutan (yang akan mengambil halaman), tetapi langsung lompat ke titik penutupnya. Dia mengutip Bjarne yang mengatakan: "optimasi seluruh program dapat digunakan untuk menghilangkan tabel fungsi virtual yang tidak terpakai dan data RTTI. Analisis semacam ini sangat cocok untuk program yang relatif kecil yang tidak menggunakan tautan dinamis."

Dia mengkritik ini dengan membuat klaim yang tidak didukung bahwa "Ini adalah masalah yang sangat sulit", bahkan sejauh membandingkannya dengan masalah penghentian. Pada kenyataannya, itu bukan semacam itu - pada kenyataannya, linker disertakan dengan Zortech C ++ (cukup banyak kompiler C ++ pertama untuk MS-DOS, kembali pada 1980-an) melakukan hal ini. Memang benar bahwa sulit untuk memastikan bahwa setiap bit data yang mungkin tidak ada telah dihilangkan, tetapi masih sepenuhnya masuk akal untuk melakukan pekerjaan yang cukup adil.

Terlepas dari itu, bagaimanapun, poin yang jauh lebih penting adalah bahwa ini sama sekali tidak relevan bagi kebanyakan programmer dalam hal apa pun. Seperti yang kita ketahui yang telah membongkar sedikit kode, kecuali jika Anda menulis bahasa rakitan tanpa pustaka sama sekali, file executable Anda hampir pasti berisi sejumlah "barang" (baik kode dan data, dalam kasus tertentu) yang Anda mungkin bahkan tidak tahu, belum lagi benar-benar menggunakan. Bagi kebanyakan orang, sebagian besar waktu, itu tidak masalah - kecuali jika Anda mengembangkan untuk sistem tertanam terkecil, bahwa konsumsi penyimpanan tambahan sama sekali tidak relevan.

Pada akhirnya, memang benar bahwa kata-kata kasar ini memang memiliki substansi yang sedikit lebih banyak daripada kebodohan Linus - tapi itu justru memberikan penghinaan dengan pujian samar yang layak diterima.


1

Sebagai seorang programmer C yang harus kode dalam C ++ karena keadaan yang tidak dapat dihindari, inilah pengalaman saya. Ada beberapa hal yang saya gunakan yaitu C ++ dan sebagian besar menempel pada C. Alasan utamanya adalah karena saya tidak mengerti C ++ dengan baik. Saya / tidak memiliki mentor untuk menunjukkan kepada saya seluk-beluk C ++ dan bagaimana menulis kode yang baik di dalamnya. Dan tanpa panduan dari kode C ++ yang sangat sangat baik, sangat sulit untuk menulis kode yang baik dalam C ++. IMHO ini adalah kelemahan terbesar dari C ++ karena C ++ coders yang baik bersedia untuk memegang pemula sulit didapat.

Beberapa hit kinerja yang saya lihat biasanya karena alokasi memori magis dari STL (ya, Anda dapat mengubah pengalokasi, tetapi siapa yang melakukannya ketika ia mulai dengan C ++?). Anda biasanya mendengar argumen oleh para ahli C ++ bahwa vektor dan array menawarkan kinerja yang sama, karena vektor menggunakan array secara internal dan abstraksi super efisien. Saya telah menemukan ini benar dalam praktiknya untuk akses vektor dan memodifikasi nilai yang ada. Tetapi tidak benar untuk menambahkan entri baru, konstruksi dan penghancuran vektor. gprof menunjukkan bahwa secara kumulatif 25% waktu untuk aplikasi dihabiskan dalam konstruktor vektor, destruktor, memmove (untuk relokasi seluruh vektor untuk menambahkan elemen baru) dan operator vektor kelebihan beban lainnya (seperti ++).

Dalam aplikasi yang sama, vektor somethingSmall digunakan untuk mewakili sesuatuBig. Tidak perlu untuk akses acak dari sesuatu yang kecil di somethingBig. Masih vektor digunakan sebagai pengganti daftar. Alasan mengapa vektor digunakan? Karena pembuat kode asli akrab dengan array seperti sintaks vektor dan tidak terlalu terbiasa dengan iterator yang diperlukan untuk daftar (ya dia berasal dari latar belakang C). Terus membuktikan bahwa banyak panduan dari para ahli diperlukan untuk mendapatkan C ++ dengan benar. C menawarkan begitu sedikit konstruksi dasar tanpa abstraksi sama sekali, sehingga Anda bisa memperbaikinya lebih mudah daripada C ++.



0

STL dan boost bersifat portabel, pada level kode sumber. Saya kira apa yang Linus bicarakan adalah bahwa C ++ tidak memiliki ABI (aplikasi binary interface). Jadi, Anda perlu mengkompilasi semua pustaka yang Anda tautkan, dengan versi kompiler yang sama dan dengan sakelar yang sama, atau batasi diri Anda dengan C ABI di batas dll. Saya juga menemukan annyoing itu .. tetapi kecuali jika Anda membuat perpustakaan pihak ke-3, Anda harus dapat mengendalikan lingkungan build Anda. Saya menemukan membatasi diri ke C ABI tidak sepadan dengan masalahnya. Kemudahan untuk meneruskan string, vektor, dan smart pointer dari satu dll ke yang lain sepadan dengan kesulitan karena harus membangun kembali semua perpustakaan ketika meningkatkan kompiler atau mengubah sakelar kompiler. Aturan emas yang saya ikuti adalah:

-Inherit untuk menggunakan kembali antarmuka, bukan implementasi

Agregasi yang lebih disukai daripada warisan

-Memilih jika memungkinkan, fungsi bebas untuk metode anggota

-Selalu gunakan idiom RAII untuk membuat kode Anda sangat aman. Hindari mencoba menangkap.

-Gunakan pointer cerdas, hindari pointer telanjang (tidak dimiliki)

Semantik nilai -Pilih untuk referensi semantik

-Jangan menemukan kembali roda, gunakan stl dan boost

-Gunakan idiom Pimpl untuk menyembunyikan privat dan / atau untuk menyediakan firewall kompiler


-6

Tidak menempatkan final ;pada akhir deklarasi clase, setidaknya dalam beberapa versi VC.


4
Ini mungkin merupakan kesalahan yang sangat umum untuk pemula (seperti hampir semua orang masih mempelajari sintaksis dasar), tetapi apakah ada banyak yang akan menyebut diri mereka kompeten dan masih menemukan kesalahan ini patut diperhatikan?
Fred Nurk

1
Menulisnya hanya karena kompiler memberi Anda kesalahan yang tidak ada hubungannya dengan kurangnya titik koma.
Marco Mustapic

2
ya, kesalahan yang sama persis adalah apa yang Anda dapatkan dari kompiler C.
Mircea Chirea
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.