Hampir tidak ada meskipun ini diakui sebagai jawaban yang aneh, dan mungkin tidak cocok untuk semua orang.
Tetapi saya merasa jauh lebih berguna dalam kasus pribadi saya untuk menyimpan semua instance dari tipe tertentu dalam urutan pusat, akses acak (thread-safe), dan sebagai gantinya bekerja dengan indeks 32-bit (alamat relatif, yaitu) , daripada petunjuk absolut.
Sebagai permulaan:
- Ini membagi dua persyaratan memori pointer analog pada platform 64-bit. Sejauh ini saya tidak pernah membutuhkan lebih dari ~ 4,29 miliar contoh tipe data tertentu.
- Itu memastikan bahwa semua instance dari jenis tertentu,
T
,, tidak akan pernah terlalu tersebar di memori. Itu cenderung mengurangi kesalahan cache untuk semua jenis pola akses, bahkan melintasi struktur yang ditautkan seperti pohon jika node dihubungkan bersama menggunakan indeks daripada pointer.
- Data paralel menjadi mudah untuk diasosiasikan menggunakan array paralel murah (atau array jarang), bukan pohon atau tabel hash.
- Set persimpangan dapat ditemukan dalam waktu linier atau lebih baik menggunakan, katakanlah, bitet paralel.
- Kita bisa radix mengurutkan indeks dan mendapatkan pola akses sekuensial yang sangat ramah cache.
- Kita dapat melacak berapa banyak contoh bagaimana tipe data tertentu telah dialokasikan.
- Minimalkan jumlah tempat yang harus berurusan dengan hal-hal seperti keselamatan pengecualian, jika Anda peduli tentang hal-hal semacam itu.
Yang mengatakan, kenyamanan adalah kelemahan serta keamanan jenis. Kita tidak bisa mengakses sebuah instance dari T
tanpa akses ke kedua kontainer dan indeks. Dan data lama yang biasa tidak int32_t
memberi tahu kita tentang tipe data apa yang dirujuknya, jadi tidak ada tipe yang aman. Kami tidak sengaja dapat mencoba mengakses Bar
menggunakan indeks untuk Foo
. Untuk mengurangi masalah kedua saya sering melakukan hal semacam ini:
struct FooIndex
{
int32_t index;
};
Kelihatannya konyol tapi itu memberi saya kembali jenis keamanan sehingga orang tidak dapat secara tidak sengaja mencoba mengakses Bar
melalui indeksFoo
tanpa kesalahan kompiler. Untuk sisi kenyamanan, saya hanya menerima sedikit ketidaknyamanan.
Hal lain yang dapat menjadi ketidaknyamanan utama bagi orang-orang adalah bahwa saya tidak dapat menggunakan polimorfisme berbasis warisan gaya OOP, karena itu akan membutuhkan penunjuk dasar yang dapat menunjuk ke semua jenis subtipe berbeda dengan ukuran dan persyaratan penyelarasan yang berbeda. Tapi saya tidak menggunakan banyak warisan hari ini - lebih suka pendekatan ECS.
Adapun shared_ptr
, saya mencoba untuk tidak menggunakannya terlalu banyak. Sebagian besar waktu saya merasa tidak masuk akal untuk berbagi kepemilikan, dan melakukan hal itu secara sembarangan dapat menyebabkan kebocoran logis. Seringkali setidaknya pada level tinggi, satu hal cenderung menjadi milik satu hal. Di mana saya sering merasa tergoda untuk menggunakannya shared_ptr
adalah memperpanjang umur suatu objek di tempat-tempat yang tidak terlalu banyak berurusan dengan kepemilikan, seperti hanya fungsi lokal di utas untuk memastikan objek tidak hancur sebelum utas selesai menggunakannya.
Untuk mengatasi masalah itu, alih-alih menggunakan shared_ptr
atau GC atau sesuatu seperti itu, saya sering memilih tugas jangka pendek yang berjalan dari kumpulan utas, dan membuatnya jadi jika utas itu meminta untuk menghancurkan suatu objek, bahwa penghancuran yang sebenarnya ditangguhkan ke brankas. waktu ketika sistem dapat memastikan bahwa tidak ada utas yang perlu mengakses jenis objek tersebut.
Saya kadang-kadang masih menggunakan penghitungan ulang tetapi memperlakukannya seperti strategi upaya terakhir. Dan ada beberapa kasus di mana benar-benar masuk akal untuk berbagi kepemilikan, seperti penerapan struktur data yang persisten, dan di sana saya merasa masuk akal untuk shared_ptr
segera meraihnya.
Jadi bagaimanapun, saya kebanyakan menggunakan indeks, dan menggunakan pointer mentah dan pintar hemat. Saya suka indeks dan jenis pintu yang terbuka ketika Anda tahu benda Anda disimpan secara bersebelahan, dan tidak tersebar di ruang memori.