pointer non-opsional vs referensi non-const di C ++

12

Dalam Fitur C ++ Lainnya, Argumen Referensi dari Panduan Gaya Google C ++ , saya membaca bahwa referensi non-const tidak boleh digunakan.

Semua parameter yang dilewati oleh referensi harus diberi label const.

Jelas bahwa melihat pemanggilan fungsi yang menggunakan referensi sebagai argumen benar-benar membingungkan bagi programmer C, tetapi C dan C ++ adalah bahasa yang berbeda sekarang. Jika parameter output diperlukan , menggunakan pointer untuk parameter output yang diperlukan, dapat menyebabkan seluruh fungsi tubuh dilewati, yang membuat implementasi fungsi lebih rumit (secara formal meningkatkan kompleksitas siklomatik dan kedalaman fungsi).

Saya ingin membuat kode C ++ semudah memahami / mempertahankan mungkin, jadi saya umumnya tertarik untuk membaca panduan gaya pengkodean. Tetapi untuk mengadaptasi praktik terbaik dalam sebuah tim, saya pikir memahami alasan di balik elemen panduan gaya adalah faktor penting.

Apakah referensi non-const benar-benar buruk? Apakah melarangnya hanya khusus Google atau itu aturan yang diterima secara umum? Apa yang membenarkan upaya ekstra untuk mengimplementasikan parameter output sebagai pointer?

Serigala
sumber
2
"Menggunakan pointer untuk itu menyebabkan seluruh fungsi tubuh dilewati" eh, apa?
ratchet freak
@ratchetfreak Saya mencoba mengklarifikasi ini. Saya akui bahwa fungsi seperti ini mungkin menunjukkan beberapa kekurangan desain. Suatu pointer selalu secara formal opsional sehingga harus diperiksa sebelum menentukannya.
Wolf
4
Panduan gaya C ++ Google cukup terbelakang. Menurut pendapat subjektif saya, itu harus dibakar.
Siyuan Ren
Adapun item khusus ini, saya pikir alasannya adalah memaksa pemrogram untuk menulis ampersand ketika argumen dapat dimutasi menunjukkan niat yang lebih jelas.
Siyuan Ren
4
Panduan Gaya Google ditulis sebagaimana adanya, untuk mendukung kode homogen dalam proyek lawas Google. Jika Anda tidak mengerjakan proyek lawas (yang ditulis dengan panduan gaya ini sejak awal), Anda mungkin tidak boleh menggunakannya (ini menentukan banyak aturan yang tidak baik untuk kode baru (c ++ 11, c ++ 14 , c ++ 17)).
utnapistim

Jawaban:

18

Alasan di balik panduan gaya Google hanya untuk membuatnya jelas dari situs panggilan fungsi apakah suatu parameter adalah parameter input atau parameter output. (Lihat di sini untuk diskusi lebih lanjut.) Bahasa lain membuat parameter eksplisit dengan desain; C #, misalnya, memiliki outkata kunci yang harus digunakan di situs panggilan . Karena C ++ tidak membuatnya eksplisit, Google memilih untuk menggunakan const ref. versus pointer untuk membuatnya lebih jelas.

Apakah ini hanya aturan Google? Tidak, tapi saya ragu ini sangat luas. Saya rasa saya belum melihatnya di luar panduan gaya Google dan grup yang secara eksplisit mematuhi bagian dari panduan gaya Google. (Misalnya, saya menyukai ide itu ketika saya pertama kali membaca panduan gaya Google tahun yang lalu dan telah menggunakannya untuk beberapa kode saya sendiri.)

Secara khusus, Pedoman Inti C ++ yang baru diumumkan lebih suka nilai pengembalian ke parameter output untuk (hampir) semuanya dan menggunakan referensi non-konstanta untuk yang lainnya. Penggunaan pointer versus referensi Google mungkin membuat parameter output lebih jelas, tetapi nilai kembali masih lebih jelas. Sekarang C ++ 11 memiliki gerakan terstandarisasi (rvalue reference,, &&untuk membuat pengembalian banyak jenis menjadi murah) dan tupel (memungkinkan cara mudah untuk mengembalikan beberapa nilai), banyak kasus penggunaan untuk parameter yang keluar tidak lagi berlaku.

Panduan Inti C ++ memiliki beberapa nama besar (Bjarne Stroustrup, Herb Sutter) di belakangnya, didukung oleh Microsoft, dan merangkul fitur-fitur C ++ terbaru (tidak seperti panduan gaya Google), jadi saya berharap rekomendasinya lebih populer daripada Google.

Josh Kelley
sumber
Terima kasih atas jawaban Anda (juga untuk kunjungan singkat ke C #). Peninjauan yang mudah tentu saja merupakan poin penting, terutama dalam proyek Open Source. Dengan pengembalian murah di C ++ modern, pertimbangan ini akan kehilangan kepentingannya. Dengan perangkat lunak lawas yang lebih lama dan kompiler yang sudah tua mungkin masih membantu.
Wolf
Saya tidak melupakannya, tetapi C + + Core Guidelines tidak secepat itu. Sangat menarik bahwa itu Filsafat menunjukkan alasan di balik aturan dan juga pandangan modern tentang pemrograman ("Mengungkapkan ide langsung dalam kode" membaca sedikit seperti Zen python) sebagai cara untuk berkomunikasi.
Wolf
Tambahan: tautan langsung ke bagian Filsafat pada Pedoman Kode C ++.
Wolf
1

Ada 2 opsi untuk berurusan dengan pointer yang tidak valid yang dimasukkan, pemeriksaan pertama dan pengembalian awal atau membiarkannya menjadi perilaku yang tidak terdefinisi (jika Anda lebih peduli tentang kecepatan daripada ketahanan).

Memeriksa sesederhana:

void foo(void* buffer){
    if(buffer == nullptr)
        return;

    //actually foo

    // note no increase in indentation required

}

Jenis pemeriksaan ini umumnya diterima sebagai pemeriksaan parameter. Jika Anda melihat kode itu cukup jelas bahwa Anda mengharapkan pointer non-null diteruskan dan kembali lebih awal jika tidak. Ini membuat Anda tidak terlalu khawatir tentang pointer yang tidak valid.

aneh ratchet
sumber
Yah, saya memikirkan pola ini dan merasa itu masuk akal. Sayangnya itu terlihat tidak sejelas assert(buffer);Mengetahui bahwa pernyataan hanya aktif untuk versi debug, saya kadang-kadang berharap ada rt_assert(buffer);yang melempar pengecualian. Lekukan yang returnterlihat agak berbahaya ... BTW: cuplikan kode Anda adalah ilustrasi yang bagus dari pertanyaan saya tentang petunjuk untuk keluaran.
Wolf
1

Itu datang ke pengamatan Anda If an output parameter is required.

Satu-satunya tempat di mana tanda tangan fungsi diperlukan untuk memiliki parameter output adalah ketika ditentukan oleh API eksternal, dan dalam kasus seperti itu Anda hanya membungkus API eksternal dalam sesuatu yang memastikan selalu ada poinee yang valid.

Secara internal Anda menghindari parameter output dengan memperluas tipe pengembalian menjadi gabungan dari semua "out"

Caleth
sumber
Maksud Anda, satu-satunya tempat di mana saya tidak dapat memberikan pointer yang tidak wajib? Benar, tapi saya tidak yakin apakah aturan Anda The only place where...benar-benar berlaku untuk semua kasus. Seperti apa saran Anda: hindari parameter output dalam fungsi program Anda sendiri. Benar untuk program baru.
Wolf
1
Ya, hindari parameter keluaran, pilih jenis pengembalian komposit, yang diedit agar lebih jelas
Caleth