Saya ingin menarik perhatian Anda pada anti-pola, yang sering saya temui dalam kode siswa di Code Review StackExchange dan bahkan dalam sejumlah besar materi pendidikan (!) Orang lain. Mereka memiliki array, katakanlah, 5 elemen; dan kemudian, karena bilangan ajaib itu buruk, mereka memperkenalkan konstanta bernama untuk mewakili kardinalitas "5".
void example()
{
constexpr int myArraySize = 5;
int myArray[myArraySize] = {2, 7, 1, 8, 2};
...
Tapi solusinya biasa saja! Dalam kode di atas, angka lima diulangi : pertama dalam nilainya
myArraySize = 5, dan kemudian lagi saat Anda benar-benar menetapkan elemen myArray. Kode di atas sama buruknya dari sudut pandang pemeliharaan seperti:
constexpr int messageLength = 45;
const char message[messageLength] =
"Invalid input. Please enter a valid number.\n";
- yang, tentu saja, tidak seorang pun dari kita akan pernah menulis.
Kode berulang tidak bagus
Perhatikan bahwa di kedua cuplikan kode di atas, setiap kali Anda mengubah konten larik atau kata-kata pada pesan, Anda harus memperbarui dua baris kode, bukan satu. Berikut adalah contoh bagaimana pengelola dapat memperbarui kode ini dengan tidak benar :
constexpr int myArraySize = 5;
- int myArray[myArraySize] = {2, 7, 1, 8, 2};
+ int myArray[myArraySize] = {3, 1, 4};
Patch di atas terlihat seperti itu mengubah isi array dari 2,7,1,8,2 menjadi 3,1,4 , tetapi ternyata tidak! Bahkan, ia berubah ke 3,1,4,0,0 - dengan nol bantalan - karena pengelola lupa untuk menyesuaikan
myArraySizesesuai myArray.
Pendekatan yang andal
Sedangkan untuk menghitung, komputer sangat bagus dalam hal itu. Jadi, biarkan komputer menghitung!
int myArray[] = {2, 7, 1, 8, 2};
constexpr int myArraySize = std::size(myArray);
Sekarang Anda dapat mengubah konten array dari, katakanlah, 2,7,1,8,2 menjadi 3,1,4 hanya dengan mengubah satu baris kode. Anda tidak perlu menduplikasi perubahan di mana pun.
Terlebih lagi,
myArraykode sebenarnya biasanya menggunakan loop fordan / atau algoritme berdasarkan rentang iterator untuk memanipulasinya , sehingga tidak memerlukan variabel bernama sama sekali untuk menyimpan ukuran array.
for (int elt : myArray) {
use(elt);
}
std::sort(myArray.begin(), myArray.end());
std::ranges::sort(myArray);
// Warning: Unused variable 'myArraySize'
Versi "buruk" dari kode ini
myArraySizeselalu digunakan (dalam deklarasi myArray), dan oleh karena itu programmer tidak mungkin melihat bahwa itu dapat dikecualikan. Dalam versi "baik", kompiler mudah untuk mendeteksi apa yang myArraySizetidak digunakan.
Bagaimana melakukan ini dengan std::array?
Terkadang seorang programmer mengambil langkah lain menuju Sisi Gelap dan menulis:
constexpr int myArraySize = 5;
std::array<int, myArraySize> myArray = {2, 7, 1, 8, 2};
Ini harus ditulis ulang setidaknya:
std::array<int, 5> myArray = {2, 7, 1, 8, 2};
constexpr int myArraySize = myArray.size(); // std::size(myArray)
Namun, tidak ada cara mudah untuk menghilangkan penghitungan manual pada baris pertama. CTAD C ++ 17 memungkinkan Anda menulis
std::array myArray = {2, 7, 1, 8, 2};
tapi ini hanya berfungsi jika Anda membutuhkan sebuah array
int- ini tidak akan berfungsi jika Anda membutuhkan sebuah array short, misalnya, atau sebuah array uint32_t.
C ++ 20 memberi kita std :: to_array , yang memungkinkan kita untuk menulis
auto myArray = std::to_array<int>({2, 7, 1, 8, 2});
constexpr int myArraySize = myArray.size();
Perhatikan bahwa ini membuat larik C dan kemudian memindahkan (pindah-konstruksi) elemennya ke dalam
std::array. Semua contoh kami sebelumnya diinisialisasi myArraydengan daftar penginisialisasi kurung kurawal yang memicu inisialisasi agregat dan membuat instance elemen array pada tempatnya.
Bagaimanapun, semua opsi ini menghasilkan sejumlah besar contoh templat tambahan dibandingkan dengan larik C lama yang bagus (yang tidak memerlukan contoh templat). Oleh karena itu, saya sangat menyukai
T[]yang lebih baru std::array<T, N>.
Dalam C ++ 11 dan C ++ 14,
std::arrayada keuntungan ergonomis dalam mengatakan arr.size(); tetapi keuntungan itu menguap ketika C ++ 17 memberi kamistd::size(arr)dan untuk array sebaris. Tidak std::arrayada lagi keunggulan ergonomis. Gunakan jika Anda membutuhkan semantik seluruh objek variabel (meneruskan seluruh array ke fungsi! Kembalikan array dari fungsi! Tetapkan array dengan =! Bandingkan array dengan ==!), Tapi selain itu saya sarankan menghindari penggunaan std::array.
Demikian juga, saya sarankan untuk menghindari std::list, kecuali jika Anda membutuhkan kestabilan iteratornya, perekatan cepat, penyortiran tanpa mengganti elemen, dll. Saya tidak mengatakan bahwa jenis ini tidak memiliki tempat di C ++; Saya hanya mengatakan bahwa mereka memiliki "seperangkat keterampilan yang sangat spesifik" dan jika Anda tidak menggunakan keterampilan itu, kemungkinan besar Anda akan membayar lebih.
Kesimpulan: jangan memagari gerobak di depan kuda. Bahkan, gerobak itu mungkin tidak dibutuhkan. Dan jika Anda perlu menggunakan zebra untuk melakukan pekerjaan kudanya, Anda juga tidak boleh memagari gerobak di depan zebra.
Baca lebih banyak: