polymorphic_allocator: kapan dan mengapa saya harus menggunakannya?

122

Berikut adalah dokumentasi tentang cppreference , berikut adalah working draftnya.

Saya harus mengakui bahwa saya tidak mengerti apa tujuan sebenarnya polymorphic_allocatordan kapan / mengapa / bagaimana saya harus menggunakannya.
Sebagai contoh, pmr::vectormemiliki tanda tangan berikut:

namespace pmr {
    template <class T>
    using vector = std::vector<T, polymorphic_allocator<T>>;
}

Apa polymorphic_allocatortawarannya? Apa yang std::pmr::vectorditawarkan juga dalam hal kuno std::vector? Apa yang dapat saya lakukan sekarang yang tidak dapat saya lakukan sampai sekarang?
Apa tujuan sebenarnya dari pengalokasi itu dan kapan saya harus menggunakannya sebenarnya?

skypjack
sumber
1
Mereka mencoba untuk mengatasi beberapa masalah yang allocator<T>secara inheren dimilikinya. Jadi, Anda akan melihat nilainya jika Anda sering menggunakan pengalokasi.
edmz
2
Kertas yang relevan .
edmz

Jawaban:

103

Kutipan pilihan dari cppreference:

Polimorfisme runtime ini memungkinkan objek yang menggunakan polymorphic_allocator untuk berperilaku seolah-olah mereka menggunakan jenis pengalokasi yang berbeda pada waktu proses meskipun jenis pengalokasi statis identik

Masalah dengan pengalokasi "biasa" adalah bahwa mereka mengubah jenis penampung. Jika Anda menginginkan vectordengan pengalokasi khusus, Anda dapat menggunakan Allocatorparameter template:

auto my_vector = std::vector<int,my_allocator>();

Masalahnya sekarang adalah bahwa vektor ini tidak memiliki tipe yang sama dengan vektor dengan pengalokasi berbeda. Anda tidak dapat meneruskannya ke fungsi yang membutuhkan vektor pengalokasi default, misalnya, atau menetapkan dua vektor dengan jenis pengalokasi berbeda ke variabel / penunjuk yang sama, misalnya:

auto my_vector = std::vector<int,my_allocator>();
auto my_vector2 = std::vector<int,other_allocator>();
auto vec = my_vector; // ok
vec = my_vector2; // error

Pengalokasi polimorfik adalah jenis pengalokasi tunggal dengan anggota yang dapat menentukan perilaku pengalokasi melalui pengiriman dinamis daripada melalui mekanisme templat. Ini memungkinkan Anda memiliki penampung yang menggunakan alokasi khusus dan disesuaikan, tetapi masih berjenis umum.

Kustomisasi perilaku pengalokasi dilakukan dengan memberikan pengalokasi std::memory_resource *:

// define allocation behaviour via a custom "memory_resource"
class my_memory_resource : public std::pmr::memory_resource { ... };
my_memory_resource mem_res;
auto my_vector = std::pmr::vector<int>(0, &mem_res);

// define a second memory resource
class other_memory_resource : public std::pmr::memory_resource { ... };
other_memory_resource mem_res_other;
auto my_other_vector = std::pmr::vector<int>(0, &mes_res_other);

auto vec = my_vector; // type is std::pmr::vector<int>
vec = my_other_vector; // this is ok -
      // my_vector and my_other_vector have same type

Masalah utama yang tersisa, seperti yang saya lihat, adalah bahwa std::pmr::wadah masih tidak kompatibel dengan std::wadah yang setara menggunakan pengalokasi default. Anda perlu membuat beberapa keputusan pada saat Anda mendesain antarmuka yang berfungsi dengan penampung:

  • apakah mungkin penampung yang diteruskan mungkin memerlukan alokasi khusus?
  • jika demikian, haruskah saya menambahkan parameter template (untuk memungkinkan pengalokasi arbitrer) atau haruskah saya mengamanatkan penggunaan pengalokasi polimorfik?

Solusi template memungkinkan pengalokasi apa pun , termasuk pengalokasi polimorfik, tetapi memiliki kelemahan lain (ukuran kode yang dihasilkan, waktu kompilasi, kode harus diekspos dalam file header, potensi untuk "kontaminasi jenis" lebih lanjut yang terus mendorong masalah ke luar). Solusi pengalokasi polimorfik di sisi lain menentukan bahwa pengalokasi polimorfik harus digunakan. Ini menghalangi penggunaan std::penampung yang menggunakan pengalokasi default, dan mungkin berimplikasi untuk berinteraksi dengan kode lama.

Dibandingkan dengan pengalokasi biasa, pengalokasi polimorfik memang memiliki beberapa biaya kecil, seperti overhead penyimpanan penunjuk memory_resource (yang kemungkinan besar dapat diabaikan) dan biaya pengiriman fungsi virtual untuk alokasi. Masalah utama, sebenarnya, mungkin kurangnya kompatibilitas dengan kode lama yang tidak menggunakan pengalokasi polimorfik.

davmac
sumber
2
Jadi, apakah tata letak biner untuk std::pmr::kelas sangat mungkin berbeda?
Euri Pinhollow
12
@EuriPinhollow Anda tidak dapat reinterpret_castmengikuti antara std::vector<X>dan std::pmr::vector<X>, jika itu yang Anda tanyakan.
davmac
4
Untuk kasus sederhana di mana resource memori tidak bergantung pada variabel runtime, compiler yang baik akan melakukan devirtualisasi dan Anda akan mendapatkan pengalokasi polimorfik tanpa biaya tambahan (kecuali untuk menyimpan pointer yang sebenarnya bukan masalah). Saya pikir itu layak untuk disebutkan.
DeiDei
1
@ Yakk-AdamNevraumont "sebuah std::pmr::kontainer masih tidak kompatibel dengan std::kontainer yang setara menggunakan pengalokasi default" . Tidak ada operator penugasan yang ditentukan dari satu ke yang lain. Jika ragu, cobalah: godbolt.org/z/Q5BKev (kode tidak persis seperti di atas karena gcc / clang memiliki kelas alokasi polimorfik dalam namespace "percobaan").
davmac
1
@davmac Ah, jadi tidak ada template<class OtherA, std::enable_if< A can be constructed from OtherA > vector( vector<T, OtherA>&& )konstruktor. Saya tidak yakin, dan tidak tahu di mana menemukan kompiler yang memiliki pmr yang memenuhi TS.
Yakk - Adam Nevraumont
33

polymorphic_allocatoradalah ke pengalokasi khusus seperti halnya std::functionpanggilan fungsi langsung.

Ini hanya memungkinkan Anda menggunakan pengalokasi dengan penampung Anda tanpa harus memutuskan, pada titik deklarasi, yang mana. Jadi jika Anda memiliki situasi di mana lebih dari satu pengalokasi akan sesuai, Anda dapat menggunakan polymorphic_allocator.

Mungkin Anda ingin menyembunyikan pengalokasi mana yang digunakan untuk menyederhanakan antarmuka Anda, atau mungkin Anda ingin menukarnya dengan kasus runtime yang berbeda.

Pertama Anda membutuhkan kode yang membutuhkan pengalokasi, kemudian Anda harus ingin menukar mana yang digunakan, sebelum mempertimbangkan vektor pmr.

Yakk - Adam Nevraumont
sumber
7

Salah satu kelemahan pengalokasi polimorfik polymorphic_allocator<T>::pointeradalah selalu adil T*. Itu berarti Anda tidak dapat menggunakannya dengan petunjuk mewah . Jika Anda ingin melakukan sesuatu seperti menempatkan elemen a vectordalam memori bersama dan mengaksesnya melalui boost::interprocess::offset_ptrs , Anda perlu menggunakan pengalokasi non-polimorfik biasa untuk itu.

Jadi, meskipun pengalokasi polimorfik memungkinkan Anda memvariasikan perilaku alokasi tanpa mengubah jenis statis penampung, pengalokasi tersebut membatasi alokasi .

Maxpm
sumber
2
Ini adalah poin kunci dan mengecewakan. Makalah Arthur O'Dwyer's Towards yang bermakna mewah menjelajahi wilayah itu, seperti halnya bukunya "Mastering the c ++ 17 STL"
lihat
dapatkah Anda memberikan kasus penggunaan dunia nyata menggunakan pengalokasi polimorfik?
sayang