Saya memiliki kelas yang disebut Writer
yang memiliki fungsi writeVector
seperti:
void Drawer::writeVector(vector<T> vec, bool index=true)
{
for (unsigned int i = 0; i < vec.size(); i++) {
if (index) {
cout << i << "\t";
}
cout << vec[i] << "\n";
}
}
Saya mencoba untuk tidak memiliki kode duplikat, sambil tetap mengkhawatirkan kinerjanya. Dalam fungsinya, saya melakukan if (index)
pengecekan pada setiap putaran saya for
-loop, meskipun hasilnya selalu sama. Ini bertentangan dengan "mengkhawatirkan kinerja".
Saya dapat dengan mudah menghindari ini dengan menempatkan centang di luar for
-loop saya . Namun, saya akan mendapatkan banyak kode duplikat:
void Drawer::writeVector(...)
{
if (index) {
for (...) {
cout << i << "\t" << vec[i] << "\n";
}
}
else {
for (...) {
cout << vec[i] << "\n";
}
}
}
Jadi ini adalah solusi yang "buruk" untuk saya. Apa yang saya pikirkan, adalah dua fungsi pribadi, salah satunya keluar dari indeks dan kemudian memanggil yang lain. Yang lainnya hanya mengeluarkan nilainya. Namun, saya tidak tahu bagaimana menggunakannya dengan program saya, saya masih memerlukan if
cek untuk melihat mana yang harus dihubungi ...
Berdasarkan masalah tersebut, polimorfisme sepertinya solusi yang tepat. Tetapi saya tidak dapat melihat bagaimana saya harus menggunakannya di sini. Apa cara yang lebih disukai untuk memecahkan masalah semacam ini?
Ini bukan program nyata, saya hanya tertarik untuk mempelajari bagaimana masalah seperti ini harus diselesaikan.
sumber
Jawaban:
Lewati badan loop sebagai functor.Itu menjadi inline pada waktu kompilasi, tidak ada penalti kinerja.
Ide untuk meneruskan apa yang bervariasi ada di mana-mana di C ++ Standard Library. Itu disebut pola strategi.
Jika Anda diizinkan menggunakan C ++ 11, Anda dapat melakukan sesuatu seperti ini:
Kode ini tidak sempurna tetapi Anda mengerti.
Di C ++ 98 lama terlihat seperti ini:
Sekali lagi, kode tersebut jauh dari sempurna tetapi memberi Anda ide.
sumber
for(int i=0;i<100;i++){cout<<"Thank you!"<<endl;}
: D Ini adalah jenis solusi yang saya cari, ini bekerja dengan sangat baik :) Anda dapat memperbaikinya dengan sedikit komentar (awalnya sulit memahaminya), tapi saya mengerti jadi tidak masalah :)cout << e << "\n";
) masih akan ada beberapa duplikasi kode.Jika memang demikian, branch predictor tidak akan memiliki masalah dalam memprediksi hasil (konstan). Dengan demikian, ini hanya akan menyebabkan overhead ringan untuk kesalahan prediksi dalam beberapa iterasi pertama. Tidak ada yang perlu dikhawatirkan dalam hal performa
Dalam hal ini saya menganjurkan untuk menjaga tes di dalam loop untuk kejelasan.
sumber
std::cout
)Untuk memperluas jawaban Ali, yang benar-benar benar tetapi masih menduplikasi beberapa kode (bagian dari badan perulangan, sayangnya hal ini hampir tidak dapat dihindari saat menggunakan pola strategi) ...
Memang dalam kasus khusus ini duplikasi kode tidak banyak tetapi ada cara untuk menguranginya lebih banyak lagi, yang berguna jika badan fungsi lebih besar dari hanya beberapa instruksi .
Kuncinya adalah menggunakan kemampuan kompiler untuk melakukan penghapusan kode lipat / mati secara konstan . Kita dapat melakukannya dengan memetakan nilai runtime secara manual ke nilai
index
waktu kompilasi (mudah dilakukan jika jumlah kasus terbatas - dua dalam kasus ini) dan menggunakan argumen template non-tipe yang dikenal pada kompilasi -waktu:Dengan cara ini kita berakhir dengan kode terkompilasi yang setara dengan contoh kode kedua Anda (luar
if
/ dalamfor
) tetapi tanpa menduplikasi kode itu sendiri. Sekarang kita dapat membuat versi templatewriteVector
serumit yang kita inginkan, akan selalu ada satu kode yang harus dipertahankan.Perhatikan bagaimana versi template (yang mengambil konstanta waktu kompilasi dalam bentuk argumen template non-tipe) dan versi non-template (yang menggunakan variabel runtime sebagai argumen fungsi) kelebihan beban. Ini memungkinkan Anda untuk memilih versi yang paling relevan tergantung pada kebutuhan Anda, memiliki sintaks yang agak mirip dan mudah diingat dalam kedua kasus:
sumber
doWriteVector
langsung tapi saya setuju namanya disayangkan. Saya baru saja mengubahnya menjadi duawriteVector
fungsi yang kelebihan beban (satu template, yang lain fungsi biasa) sehingga hasilnya lebih homogen. Terima kasih untuk sarannya. ;)Dalam kebanyakan kasus, kode Anda sudah bagus untuk performa dan keterbacaan. Kompilator yang baik mampu mendeteksi invarian loop dan melakukan pengoptimalan yang sesuai. Pertimbangkan contoh berikut yang sangat dekat dengan kode Anda:
Saya menggunakan baris perintah berikut untuk mengkompilasinya:
Lalu, mari kita buang perakitan:
Hasil perakitan
write_vector
adalah:Kita dapat melihat, bahwa atas permintaan fungsi, kita memeriksa nilainya dan melompat ke salah satu dari dua kemungkinan loop:
Tentu saja, ini hanya berfungsi jika kompiler mampu mendeteksi bahwa suatu kondisi adalah invarian aktual. Biasanya, ini berfungsi sempurna untuk flag dan fungsi inline sederhana. Tetapi jika kondisinya "kompleks", pertimbangkan untuk menggunakan pendekatan dari jawaban lain.
sumber