Saya sudah membaca bahwa saya harus menghindari operator kenaikan postfix karena alasan kinerja (dalam kasus tertentu).
Tetapi tidakkah ini mempengaruhi pembacaan kode? Menurutku:
for(int i = 0; i < 42; i++);
/* i will never equal 42! */
Terlihat lebih baik daripada:
for(int i = 0; i < 42; ++i);
/* i will never equal 42! */
Tapi ini mungkin hanya karena kebiasaan. Memang, saya belum melihat banyak kegunaan ++i
.
Apakah kinerja yang buruk untuk mengorbankan keterbacaan, dalam hal ini? Atau apakah saya hanya buta, dan ++i
lebih mudah dibaca daripada i++
?
c++
readability
postfix
Mateen Ulhaq
sumber
sumber
i++
sebelum saya tahu itu bisa mempengaruhi kinerja++i
, jadi saya beralih. Pada awalnya yang terakhir memang terlihat sedikit aneh, tetapi setelah beberapa saat saya terbiasa dan sekarang terasa sealamii++
.++i
dani++
melakukan hal-hal yang berbeda dalam konteks tertentu, jangan menganggap mereka sama.for (type i = 0; i != 42; ++i)
. Tidak hanya bisaoperator++
kelebihan beban, tetapi juga bisaoperator!=
danoperator<
. Peningkatan awalan tidak lebih mahal dari postfix, tidak sama tidak lebih mahal daripada lebih rendah. Yang mana yang harus kita gunakan?Jawaban:
Fakta:
i ++ dan ++ i sama-sama mudah dibaca. Anda tidak suka satu karena Anda tidak terbiasa, tetapi pada dasarnya tidak ada yang bisa Anda salah artikan, jadi tidak ada lagi pekerjaan untuk membaca atau menulis.
Setidaknya dalam beberapa kasus, operator postfix akan kurang efisien.
Namun, dalam kasus 99,99%, itu tidak masalah karena (a) itu akan bertindak pada tipe sederhana atau primitif dan itu hanya masalah jika menyalin objek besar (b) itu tidak akan berada dalam kinerja bagian penting dari kode (c) Anda tidak tahu apakah kompiler akan mengoptimalkannya atau tidak, itu bisa dilakukan.
Jadi, saya sarankan menggunakan awalan kecuali Anda secara khusus membutuhkan postfix adalah kebiasaan yang baik untuk masuk, hanya karena (a) itu kebiasaan yang baik untuk menjadi tepat dengan hal-hal lain dan (b) sekali dalam bulan biru Anda akan berniat menggunakan postfix dan mendapatkannya dengan cara yang salah: jika Anda selalu menulis apa yang Anda maksudkan, itu kemungkinan kecil. Selalu ada trade-off antara kinerja dan optimisasi.
Anda harus menggunakan akal sehat Anda dan tidak mengoptimalkan mikro sampai Anda perlu, tetapi tidak akan menjadi tidak efisien untuk itu. Biasanya ini berarti: pertama, singkirkan segala konstruksi kode yang tidak efisien yang tidak dapat diterima bahkan dalam kode non-waktu-kritis (biasanya sesuatu yang mewakili kesalahan konseptual yang mendasar, seperti melewatkan 500MB objek dengan nilai tanpa alasan); dan kedua, dari setiap cara penulisan kode lainnya, pilih yang paling jelas.
Namun, di sini, saya percaya jawabannya sederhana: Saya percaya menulis awalan kecuali jika Anda secara khusus membutuhkan postfix adalah (a) sangat sedikit lebih jelas dan (b) sangat sedikit lebih mungkin lebih efisien, jadi Anda harus selalu menuliskannya secara default, tetapi jangan khawatir tentang hal itu jika Anda lupa.
Enam bulan yang lalu, saya berpikir sama dengan Anda, bahwa i ++ lebih alami, tapi ini murni yang biasa Anda lakukan.
EDIT 1: Scott Meyers, dalam "C ++ Lebih Efektif" yang secara umum saya percayai tentang hal ini, mengatakan Anda harus secara umum menghindari penggunaan operator postfix pada tipe yang ditentukan pengguna (karena satu-satunya implementasi yang waras dari fungsi kenaikan postfix adalah membuat salinan objek, panggil fungsi awalan increment untuk melakukan kenaikan, dan kembalikan salinannya, tetapi operasi penyalinan bisa mahal).
Jadi, kita tidak tahu apakah ada aturan umum tentang (a) apakah itu benar hari ini, (b) apakah itu juga berlaku (kurang begitu) untuk tipe intrinsik (c) apakah Anda harus menggunakan "++" pada apa pun lebih dari kelas iterator yang ringan. Tetapi untuk semua alasan yang saya jelaskan di atas, tidak masalah, lakukan apa yang saya katakan sebelumnya.
EDIT 2: Ini merujuk pada praktik umum. Jika Anda berpikir itu TIDAK penting dalam beberapa contoh tertentu, maka Anda harus membuat profil dan melihatnya. Pembuatan profil mudah dan murah dan berfungsi. Mendedikasikan dari prinsip pertama apa yang perlu dioptimalkan adalah sulit dan mahal dan tidak bekerja.
sumber
i++
daripada++i
adalah karena nama bahasa pemrograman populer tertentu yang dirujuk dalam pertanyaan / jawaban ini ...Selalu kode untuk programmer pertama dan komputer kedua.
Jika ada perbedaan kinerja, setelah kompiler mengarahkan pandangan ahli atas kode Anda, DAN Anda bisa mengukurnya DAN itu penting - maka Anda bisa mengubahnya.
sumber
GCC menghasilkan kode mesin yang sama untuk kedua loop.
Kode C
Assembly Code (dengan komentar saya)
sumber
Sekarang ini sudah keluar dari jalan kita, mari kita buat pilihan kita dengan waras :
++i
: kenaikan awalan , tambah nilai saat ini dan hasilkan hasilnyai++
: kenaikan postfix , salin nilainya, tambah nilainya saat ini, hasilkan salinannyaKecuali jika diperlukan salinan nilai lama, gunakan penambahan postfix adalah cara bulat untuk menyelesaikan sesuatu.
Ketidaktepatan berasal dari kemalasan, selalu gunakan konstruk yang mengekspresikan niat Anda dengan cara yang paling langsung, ada sedikit peluang yang bisa disalahpahami oleh niat Anda di masa depan.
Meskipun ini (benar-benar) kecil di sini, ada kalanya saya benar-benar bingung dengan membaca kode: Saya benar-benar bertanya-tanya apakah maksud dan ekspres yang sebenarnya sesuai, dan tentu saja, setelah beberapa bulan, mereka (atau saya) juga tidak ingat ...
Jadi, tidak masalah apakah itu cocok untuk Anda, atau tidak. Rangkullah KISS . Dalam beberapa bulan Anda akan menghindari praktik lama Anda.
sumber
Di C ++, Anda bisa membuat perbedaan kinerja yang substansial jika ada kelebihan operator yang terlibat, terutama jika Anda sedang menulis kode templated dan tidak tahu iterator apa yang mungkin diteruskan. Logika di balik iterator X mana pun mungkin substansial dan signifikan- yaitu lambat, dan tidak dioptimalkan oleh kompiler.
Tapi ini bukan kasus di C, di mana Anda tahu itu hanya akan menjadi tipe sepele, dan perbedaan kinerja sepele dan kompiler dapat dengan mudah mengoptimalkannya.
Jadi tip: Anda memprogram dalam C, atau dalam C ++, dan pertanyaan berhubungan dengan satu atau yang lain, tidak keduanya.
sumber
Kinerja dari kedua operasi ini sangat tergantung pada arsitektur yang mendasarinya. Kita harus meningkatkan nilai yang disimpan dalam memori, yang berarti bahwa bottleneck von Neumann adalah faktor pembatas dalam kedua kasus.
Dalam kasus ++ i, kita harus
Dalam kasus i ++, kita harus
Operator ++ dan - melacak asal mereka ke set instruksi PDP-11. PDP-11 dapat melakukan peningkatan pasca-otomatis pada register. Itu juga bisa melakukan pra-pengurangan otomatis pada alamat efektif yang terkandung dalam register. Dalam kedua kasus tersebut, kompiler hanya dapat mengambil keuntungan dari operasi tingkat mesin ini jika variabel yang dimaksud adalah variabel "register".
sumber
Jika Anda ingin tahu apakah ada sesuatu yang lambat, ujilah. Ambil BigInteger atau yang setara, tempelkan di loop yang sama untuk menggunakan kedua idiom, pastikan bagian dalam loop tidak dioptimalkan, dan waktu keduanya.
Setelah membaca artikel itu, saya merasa tidak terlalu meyakinkan, karena tiga alasan. Pertama, kompiler harus dapat mengoptimalkan pembuatan objek yang tidak pernah digunakan. Dua,
i++
konsepnya idiomatis untuk numerik untuk loop , sehingga kasus yang saya lihat benar-benar terpengaruh terbatas. Tiga, mereka memberikan argumen teoretis murni, tanpa nomor untuk mendukungnya.Berdasarkan alasan # 1 khususnya, tebakan saya adalah bahwa ketika Anda benar-benar melakukan pengaturan waktu, mereka akan berada tepat di sebelah satu sama lain.
sumber
Pertama-tama itu tidak mempengaruhi IMO keterbacaan. Ini bukan apa yang biasa Anda lihat, tetapi itu hanya sebentar sebelum Anda terbiasa.
Kedua, kecuali jika Anda menggunakan banyak operator postfix dalam kode Anda, Anda tidak akan melihat banyak perbedaan. Argumen utama untuk tidak menggunakannya bila mungkin adalah bahwa salinan dari nilai var asli harus disimpan sampai akhir argumen di mana var asli masih bisa digunakan. Itu 32bit atau 64bit tergantung pada arsitektur. Itu sama dengan 4 atau 8 byte atau 0,00390625 atau 0,0078125 MB. Peluangnya sangat tinggi, kecuali jika Anda menggunakan banyak dari mereka yang perlu disimpan untuk jangka waktu yang sangat lama dengan sumber daya dan kecepatan komputer saat ini Anda bahkan tidak akan melihat perbedaan saat beralih dari postfix ke prefix.
EDIT: Lupakan bagian yang tersisa ini karena kesimpulan saya terbukti salah (kecuali untuk bagian ++ i dan i ++ tidak selalu melakukan hal yang sama ... itu masih benar).
Juga telah ditunjukkan sebelumnya bahwa mereka tidak melakukan hal yang sama dalam sebuah kasus. Berhati-hatilah untuk beralih jika Anda memutuskan untuk melakukannya. Saya tidak pernah mencobanya (saya selalu menggunakan postfix) jadi saya tidak tahu pasti tapi saya pikir mengubah dari postfix ke prefix akan menghasilkan hasil yang berbeda: (sekali lagi saya bisa salah ... tergantung pada kompiler / penerjemah juga)
sumber
Saya pikir secara semantik,
++i
lebih masuk akal daripadai++
, jadi saya akan tetap pada yang pertama, kecuali itu umum untuk tidak melakukannya (seperti di Jawa, di mana Anda harus menggunakani++
karena itu banyak digunakan).sumber
Ini bukan hanya tentang kinerja.
Terkadang Anda ingin menghindari penerapan penyalinan sama sekali, karena itu tidak masuk akal. Dan karena penggunaan penambahan awalan tidak bergantung pada ini, lebih mudah untuk tetap menggunakan formulir awalan.
Dan menggunakan peningkatan berbeda untuk tipe primitif dan tipe kompleks ... itu benar-benar tidak dapat dibaca.
sumber
Kecuali Anda benar-benar membutuhkannya, saya akan tetap menggunakan ++ i. Dalam kebanyakan kasus, inilah yang ingin dicapai. Ini tidak terlalu sering Anda butuhkan i ++, dan Anda selalu harus berpikir dua kali ketika membaca konstruksi seperti itu. Dengan ++ i, mudah: Anda menambahkan 1, menggunakannya, dan kemudian saya masih sama.
Jadi, saya setuju sepenuh hati dengan @martin beckett: buat sendiri lebih mudah, itu sudah cukup sulit.
sumber