Saya memiliki kelas dengan anggota unique_ptr.
class Foo {
private:
std::unique_ptr<Bar> bar;
...
};
Bilah adalah kelas pihak ketiga yang memiliki fungsi create () dan fungsi destroy ().
Jika saya ingin menggunakan std::unique_ptr
dengan itu dalam fungsi yang berdiri sendiri yang bisa saya lakukan:
void foo() {
std::unique_ptr<Bar, void(*)(Bar*)> bar(create(), [](Bar* b){ destroy(b); });
...
}
Apakah ada cara untuk melakukan ini dengan std::unique_ptr
sebagai anggota kelas?
c++
c++11
move-semantics
unique-ptr
huitlarc
sumber
sumber
std::unique_ptr<Bar, decltype(&destroy)> ptr_;
unique_ptr
(mereka semua harus menyimpan pointer fungsi bersama dengan pointer ke data aktual), membutuhkan melewati fungsi penghancuran setiap kali, itu tidak dapat inline (karena template tidak bisa mengkhususkan diri pada fungsi spesifik, hanya tanda tangan), dan harus memanggil fungsi melalui pointer (lebih mahal daripada panggilan langsung). Kedua jawaban rici dan Deduplicator menghindari semua biaya ini dengan mengkhususkan diri pada functor.Dimungkinkan untuk melakukan ini dengan bersih menggunakan lambda di C ++ 11 (diuji dalam G ++ 4.8.2).
Mengingat ini dapat digunakan kembali
typedef
:Kamu bisa menulis:
Misalnya, dengan
FILE*
:Dengan ini Anda mendapatkan manfaat pembersihan dengan pengecualian-aman menggunakan RAII, tanpa perlu mencoba / menangkap kebisingan.
sumber
std::function
dalam definisi atau sejenisnya?std::function
. Lambda atau kelas khusus seperti dalam jawaban yang diterima dapat diuraikan tidak seperti solusi ini. Tetapi pendekatan ini memiliki keuntungan jika Anda ingin mengisolasi semua implementasi dalam modul khusus.deleted_unique_ptr<Foo> foo(new Foo(), customdeleter);
jikacustomdeleter
mengikuti konvensi (mengembalikan konvensi dan menerima pointer mentah sebagai argumen).Anda hanya perlu membuat kelas deleter:
dan berikan sebagai argumen templat dari
unique_ptr
. Anda masih harus menginisialisasi unique_ptr di konstruktor Anda:Sejauh yang saya tahu, semua pustaka c ++ populer mengimplementasikan ini dengan benar; Karena
BarDeleter
tidak benar - benar memiliki keadaan apa pun, tidak perlu menempati ruang apa pun di Internetunique_ptr
.sumber
struct BarDeleter
) kestd::unique_ptr
(std::unique_ptr<Bar, BarDeleter>
) yang memungkinkanstd::unique_ptr
konstruktor membuat instance Deleter sendiri. yaitu kode berikut diizinkanstd::unique_ptr<Bar, BarDeleter> bar[10];
typedef std::unique_ptr<Bar, BarDeleter> UniqueBarPtr
unique_ptr
, tidak perlu memberikan instance dari deleter saat membangun), dan menambahkan manfaat dapat digunakan distd::unique_ptr<Bar>
mana saja tanpa perlu mengingat untuk menggunakantypedef
penyedia khusus atau secara eksplisit parameter templat kedua. (Untuk lebih jelasnya, ini adalah solusi yang baik, saya memberikan suara, tetapi itu menghentikan satu langkah di belakang dari solusi yang mulus)Kecuali Anda harus dapat mengubah deleter saat runtime, saya akan sangat menyarankan menggunakan tipe deleter khusus. Misalnya, jika menggunakan pointer fungsi untuk deleter Anda
sizeof(unique_ptr<T, fptr>) == 2 * sizeof(T*)
,. Dengan kata lain, setengah dari byteunique_ptr
objek terbuang sia-sia.Menulis custom deleter untuk membungkus setiap fungsi memang merepotkan. Untungnya, kita dapat menulis sebuah tipe yang ditempel pada fungsi:
Sejak C ++ 17:
Sebelum ke C ++ 17:
sumber
deleter_from_fn
memang begitu.Anda cukup menggunakan
std::bind
dengan fungsi penghancuran Anda.Tapi tentu saja Anda juga bisa menggunakan lambda.
sumber
Anda tahu, menggunakan custom deleter bukanlah cara terbaik, karena Anda harus menyebutkannya di seluruh kode Anda.
Alih-alih, karena Anda diizinkan untuk menambahkan spesialisasi ke kelas tingkat namespace
::std
selama jenis kustom terlibat dan Anda menghormati semantik, lakukan itu:Spesialisasi
std::default_delete
:Dan mungkin juga melakukan
std::make_unique()
:sumber
std
membuka kaleng cacing yang sama sekali baru. Perhatikan juga bahwa spesialisasi daristd::make_unique
tidak diperbolehkan posting C ++ 20 (sehingga tidak boleh dilakukan sebelumnya) karena C ++ 20 melarang spesialisasi hal-halstd
yang bukan templat kelas (std::make_unique
adalah templat fungsi). Perhatikan bahwa Anda mungkin juga akan berakhir dengan UB jika pointer yang masukstd::unique_ptr<Bar>
tidak dialokasikan daricreate()
, tetapi dari beberapa fungsi alokasi lainnya.std::default_delete
memenuhi persyaratan templat asli. Saya akan membayangkan itustd::default_delete<Foo>()(p)
akan menjadi cara yang valid untuk menulisdelete p;
, jadi jikadelete p;
akan valid untuk menulis (yaitu jikaFoo
sudah lengkap), ini tidak akan menjadi perilaku yang sama. Selain itu, jikadelete p;
tidak valid untuk menulis (Foo
tidak lengkap), ini akan menentukan perilaku baru untukstd::default_delete<Foo>
, daripada menjaga perilaku yang sama.make_unique
spesialisasi bermasalah, tapi aku pasti menggunakanstd::default_delete
kelebihan (tidak templated denganenable_if
, hanya untuk C struct seperti OpenSSLBIGNUM
yang menggunakan fungsi kerusakan diketahui, di mana subclassing tidak akan terjadi), dan itu jauh pendekatan yang paling mudah, karena sisa kode Anda hanya dapat digunakanunique_ptr<special_type>
tanpa harus melewati tipe functor sebagai templatedDeleter
all over, atau menggunakantypedef
/using
untuk memberi nama pada tipe kata untuk menghindari masalah itu.