Pertanyaan # 1: Apakah mendeklarasikan variabel di dalam loop merupakan praktik yang baik atau praktik yang buruk?
Saya telah membaca utas lainnya tentang apakah ada masalah kinerja (sebagian besar mengatakan tidak), dan bahwa Anda harus selalu mendeklarasikan variabel sedekat mungkin dengan tempat mereka akan digunakan. Yang saya pikirkan adalah apakah ini harus dihindari atau benar-benar disukai.
Contoh:
for(int counter = 0; counter <= 10; counter++)
{
string someString = "testing";
cout << someString;
}
Pertanyaan # 2: Apakah sebagian besar penyusun menyadari bahwa variabel telah dideklarasikan dan hanya melewatkan bagian itu, atau apakah itu benar-benar membuat tempat untuk itu dalam memori setiap kali?
c++
loops
variable-declaration
JeramyRR
sumber
sumber
Jawaban:
Ini adalah latihan yang bagus .
Dengan membuat variabel di dalam loop, Anda memastikan cakupannya dibatasi di dalam loop. Itu tidak dapat dirujuk atau dipanggil di luar loop.
Cara ini:
Jika nama variabel sedikit "generik" (seperti "i"), tidak ada risiko untuk mencampurnya dengan variabel lain dengan nama yang sama di suatu tempat nanti dalam kode Anda (juga dapat dikurangi dengan menggunakan
-Wshadow
instruksi peringatan pada GCC)Kompilator tahu bahwa ruang lingkup variabel terbatas di dalam loop, dan karena itu akan mengeluarkan pesan kesalahan yang tepat jika variabel tersebut dirujuk secara tidak sengaja di tempat lain.
Last but not least, beberapa optimasi khusus dapat dilakukan lebih efisien oleh kompiler (paling penting mendaftar alokasi), karena ia tahu bahwa variabel tidak dapat digunakan di luar loop. Misalnya, tidak perlu menyimpan hasilnya untuk digunakan kembali nanti.
Singkatnya, Anda benar untuk melakukannya.
Namun perlu dicatat bahwa variabel tidak seharusnya mempertahankan nilainya antara setiap loop. Dalam hal demikian, Anda mungkin perlu menginisialisasi setiap waktu. Anda juga dapat membuat blok yang lebih besar, mencakup loop, yang tujuan utamanya adalah mendeklarasikan variabel yang harus mempertahankan nilainya dari satu loop ke loop lainnya. Ini biasanya termasuk penghitung putaran itu sendiri.
Untuk pertanyaan # 2: Variabel dialokasikan satu kali, ketika fungsi dipanggil. Bahkan, dari perspektif alokasi, itu (hampir) sama dengan mendeklarasikan variabel di awal fungsi. Satu-satunya perbedaan adalah ruang lingkup: variabel tidak dapat digunakan di luar loop. Bahkan dimungkinkan bahwa variabel tidak dialokasikan, hanya menggunakan kembali beberapa slot gratis (dari variabel lain yang ruang lingkupnya telah berakhir).
Dengan ruang lingkup terbatas dan lebih tepat datang optimasi yang lebih akurat. Tetapi yang lebih penting, itu membuat kode Anda lebih aman, dengan lebih sedikit status (yaitu variabel) yang perlu dikhawatirkan saat membaca bagian lain dari kode.
Ini benar bahkan di luar
if(){...}
blok. Biasanya, alih-alih:lebih aman untuk menulis:
Perbedaannya mungkin tampak kecil, terutama pada contoh kecil seperti itu. Tetapi pada basis kode yang lebih besar, ini akan membantu: sekarang tidak ada risiko untuk memindahkan sejumlah
result
nilai darif1()
kef2()
blok. Masingresult
- masing sangat terbatas pada ruang lingkupnya sendiri, menjadikan perannya lebih akurat. Dari sudut pandang pengulas, ini jauh lebih baik, karena ia memiliki variabel status jarak jauh yang kurang perlu dikhawatirkan dan dilacak.Bahkan kompiler akan membantu lebih baik: dengan asumsi bahwa, di masa depan, setelah beberapa perubahan kode yang salah,
result
tidak diinisialisasi dengan benarf2()
. Versi kedua hanya akan menolak untuk bekerja, menyatakan pesan kesalahan yang jelas pada waktu kompilasi (jauh lebih baik daripada waktu berjalan). Versi pertama tidak akan menemukan apa pun, hasilnyaf1()
hanya akan diuji untuk kedua kalinya, menjadi bingung untuk hasilnyaf2()
.Informasi pelengkap
Alat open-source CppCheck (alat analisis statis untuk kode C / C ++) memberikan beberapa petunjuk yang sangat baik mengenai ruang lingkup variabel yang optimal.
Menanggapi komentar tentang alokasi: Aturan di atas benar dalam C, tetapi mungkin tidak untuk beberapa kelas C ++.
Untuk tipe dan struktur standar, ukuran variabel diketahui pada waktu kompilasi. Tidak ada yang namanya "konstruksi" di C, jadi ruang untuk variabel hanya akan dialokasikan ke stack (tanpa inisialisasi), ketika fungsi dipanggil. Itu sebabnya ada biaya "nol" ketika mendeklarasikan variabel di dalam satu loop.
Namun, untuk kelas C ++, ada hal konstruktor ini yang saya tahu jauh tentang. Saya kira alokasi mungkin tidak akan menjadi masalah, karena kompiler harus cukup pintar untuk menggunakan kembali ruang yang sama, tetapi inisialisasi kemungkinan terjadi pada setiap perulangan loop.
sumber
string
danvector
secara khusus, operator penugasan dapat menggunakan kembali buffer yang dialokasikan setiap loop, yang (tergantung pada loop Anda) mungkin penghematan waktu yang sangat besar.Secara umum, ini adalah praktik yang sangat baik untuk tetap dekat.
Dalam beberapa kasus, akan ada pertimbangan seperti kinerja yang membenarkan menarik variabel keluar dari loop.
Dalam contoh Anda, program membuat dan menghancurkan string setiap kali. Beberapa perpustakaan menggunakan optimasi string kecil (SSO), sehingga alokasi dinamis dapat dihindari dalam beberapa kasus.
Misalkan Anda ingin menghindari kreasi / alokasi yang berlebihan itu, Anda akan menuliskannya sebagai:
atau Anda dapat menarik keluar konstan:
Itu dapat menggunakan kembali ruang yang dikonsumsi variabel , dan itu bisa menarik invarian keluar dari loop Anda. Dalam kasus array char const (di atas) - array yang bisa ditarik keluar. Namun, konstruktor dan destruktor harus dieksekusi pada setiap iterasi dalam kasus suatu objek (seperti
std::string
). Dalam hal inistd::string
, 'spasi' itu termasuk pointer yang berisi alokasi dinamis yang mewakili karakter. Jadi ini:akan memerlukan penyalinan berlebihan dalam setiap kasus, dan alokasi dinamis dan gratis jika variabel berada di atas ambang batas untuk jumlah karakter SSO (dan SSO diimplementasikan oleh perpustakaan std Anda).
Melakukan ini:
masih memerlukan salinan fisik karakter di setiap iterasi, tetapi formulir dapat menghasilkan satu alokasi dinamis karena Anda menetapkan string dan implementasinya akan melihat bahwa tidak perlu mengubah ukuran alokasi dukungan string. Tentu saja, Anda tidak akan melakukan itu dalam contoh ini (karena beberapa alternatif unggul telah diperlihatkan), tetapi Anda dapat mempertimbangkannya ketika string atau konten vektor bervariasi.
Jadi apa yang Anda lakukan dengan semua opsi itu (dan banyak lagi)? Tetap sangat dekat sebagai default - sampai Anda memahami biayanya dengan baik dan tahu kapan Anda harus menyimpang.
sumber
Untuk C ++ tergantung pada apa yang Anda lakukan. OK, itu kode bodoh tapi bayangkan
Anda akan menunggu 55 detik sampai Anda mendapatkan output dari myFunc. Hanya karena setiap loop kontruktor dan destruktor bersama-sama membutuhkan 5 detik untuk selesai.
Anda akan membutuhkan 5 detik hingga Anda mendapatkan output dari myOtherFunc.
Tentu saja, ini adalah contoh gila.
Tapi itu menggambarkan bahwa itu mungkin menjadi masalah kinerja ketika setiap loop konstruksi yang sama dilakukan ketika konstruktor dan / atau destruktor membutuhkan waktu.
sumber
Saya tidak memposting untuk menjawab pertanyaan JeremyRR (karena sudah dijawab); alih-alih, saya mengirim hanya untuk memberikan saran.
Untuk JeremyRR, Anda bisa melakukan ini:
Saya tidak tahu apakah Anda sadar (saya tidak melakukannya ketika pertama kali memulai pemrograman), bahwa tanda kurung (selama mereka berpasangan) dapat ditempatkan di mana saja di dalam kode, tidak hanya setelah "jika", "untuk", " sementara ", dll.
Kode saya dikompilasi dalam Microsoft Visual C ++ 2010 Express, jadi saya tahu itu berfungsi; juga, saya telah mencoba menggunakan variabel di luar tanda kurung yang didefinisikan dan saya menerima kesalahan, jadi saya tahu bahwa variabel "dihancurkan".
Saya tidak tahu apakah ini praktik yang buruk untuk menggunakan metode ini, karena banyak tanda kurung yang tidak berlabel dapat dengan cepat membuat kode tidak dapat dibaca, tetapi mungkin beberapa komentar dapat menghapus semuanya.
sumber
Ini adalah praktik yang sangat baik, karena semua jawaban di atas memberikan aspek teoretis yang sangat baik dari pertanyaan, izinkan saya memberikan sekilas kode, saya mencoba menyelesaikan DFS melalui GEEKSFORGEEKS, saya menghadapi masalah optimisasi ...... Jika Anda mencoba untuk pecahkan kode dengan mendeklarasikan integer di luar loop akan memberikan Anda Kesalahan Optimasi ..
Sekarang letakkan bilangan bulat di dalam loop ini akan memberi Anda jawaban yang benar ...
ini sepenuhnya mencerminkan apa yang dikatakan pak @justin dalam komentar ke-2 .... coba ini di sini https://practice.geeksforgeeks.org/problems/depth-first-traversal-for-a-graph/1 . coba saja .... Anda akan mendapatkannya. Mohon bantuan ini.
sumber
flag
harus diinisialisasi ulang pada 0 setiapwhile
iterasi. Itu masalah logika, bukan masalah definisi.Bab 4.8 Struktur Blok dalam Bahasa Pemrograman K&R 2.Ed. :
Saya mungkin tidak melihat deskripsi yang relevan dalam buku seperti:
Tetapi tes sederhana dapat membuktikan asumsi yang dimiliki:
sumber