Mengapa tidak ada std::make_unique
templat fungsi di pustaka C ++ 11 standar? saya menemukan
std::unique_ptr<SomeUserDefinedType> p(new SomeUserDefinedType(1, 2, 3));
sedikit bertele-tele. Bukankah yang berikut ini akan jauh lebih baik?
auto p = std::make_unique<SomeUserDefinedType>(1, 2, 3);
Ini menyembunyikan yang new
baik dan hanya menyebutkan tipe sekali.
Bagaimanapun, ini adalah upaya saya untuk implementasi dari make_unique
:
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
Butuh waktu cukup lama untuk menyelesaikannya std::forward
, tapi saya tidak yakin apakah itu benar. Apakah itu? Apa sebenarnya std::forward<Args>(args)...
artinya? Apa yang dilakukan oleh kompiler?
c++
c++11
variadic-templates
unique-ptr
perfect-forwarding
fredoverflow
sumber
sumber
unique_ptr
mengambil parameter templat kedua yang entah bagaimana harus Anda izinkan - yang berbeda darishared_ptr
.make_unique
dengan deleter khusus, karena jelas itu mengalokasikan melalui biasa lamanew
dan karenanya harus menggunakan biasa lamadelete
:)make_unique
akan terbatas padanew
alokasi ... well, tidak apa-apa jika Anda ingin menulisnya, tapi saya bisa melihat mengapa sesuatu seperti itu bukan bagian dari standar.make_unique
templat karena konstruktorstd::unique_ptr
eksplisit, dan oleh karena itu verbose untuk kembaliunique_ptr
dari suatu fungsi. Juga, saya lebih suka menggunakanauto p = make_unique<foo>(bar, baz)
daripadastd::unique_ptr<foo> p(new foo(bar, baz))
.make_unique
akan datangC++14
, lihat isocpp.org/blog/2013/04/trip-report-iso-c-spring-2013-meetingJawaban:
Herb Sutter, ketua komite standardisasi C ++, menulis di blognya :
Dia juga memberikan implementasi yang identik dengan yang diberikan oleh OP.
Sunting:
std::make_unique
sekarang adalah bagian dari C ++ 14 .sumber
make_unique
Template fungsi sendiri tidak menjamin panggilan aman pengecualian. Itu bergantung pada konvensi, bahwa penelepon menggunakannya. Sebaliknya, pengecekan tipe statis yang ketat (yang merupakan perbedaan utama antara C ++ dan C) dibangun berdasarkan gagasan menegakkan keselamatan, melalui tipe. Dan untuk itu,make_unique
bisa berupa kelas alih-alih fungsi. Misalnya, lihat artikel blog saya dari Mei 2010. Ini juga ditautkan dari diskusi di blog Herb.make_unique
kelas, saya sekarang berpikir lebih baik untuk membuatnya menjadi fungsi yang menghasilkanmake_unique_t
, alasan untuk itu adalah masalah dengan parse yang paling sesat :-).make_unique
menawarkan jaminan pengecualian yang kuat. Atau mungkin Anda sedang mencampur alat dengan penggunaannya, dalam hal ini tidak ada fungsi yang terkecuali aman. Pertimbangkanvoid f( int *, int* ){}
, jelas-jelas menawarkanno throw
jaminan, tetapi menurut alasan Anda, itu bukan pengecualian aman, karena dapat disalahgunakan. Lebih buruk lagi,void f( int, int ) {}
tidak terkecuali aman juga !:typedef unique_ptr<int> up; f( *up(new int(5)), *up(new int(10)))
...make_unique
diimplementasikan seperti di atas dan Anda menunjuk saya untuk sebuah artikel oleh Sutter, artikel yang saya google-fu menunjuk saya untuk menyatakan bahwamake_unique
penawaran yang jaminan pengecualian yang kuat , yang bertentangan pernyataan Anda di atas. Jika Anda memiliki artikel yang berbeda saya saya tertarik membacanya. Jadi pertanyaan awal saya berdiri Bagaimanamake_unique
(sebagaimana didefinisikan di atas) tidak terkecuali aman? (Sidenote: ya, saya pikir itumake_unique
meningkatkan keamanan pengecualian di tempat-tempat di mana ia dapat diterapkan)make_unique
. Pertama saya tidak melihat bagaimana ini tidak aman, dan saya tidak melihat bagaimana menambahkan tipe tambahan akan membuatnya lebih aman . Apa yang saya tahu adalah bahwa saya tertarik untuk memahami isu-isu yang dapat dimiliki oleh implementasi ini - Saya tidak dapat melihat -, dan bagaimana implementasi alternatif akan menyelesaikannya. Apa konvensi yangmake_unique
bergantung pada? Bagaimana Anda menggunakan pengecekan tipe untuk menegakkan keamanan? Itulah dua pertanyaan yang ingin saya jawab.Bagus, tetapi Stephan T. Lavavej (lebih dikenal sebagai STL) memiliki solusi yang lebih baik
make_unique
, yang berfungsi dengan benar untuk versi array.Ini dapat dilihat pada video Core C ++ 6-nya .
Versi terbaru dari versi make_unique STL sekarang tersedia sebagai N3656 . Versi ini diadopsi menjadi konsep C ++ 14.
sumber
make_unique
harus masuk dalam tajuk. Header tidak boleh mengimpor namespace (lihat Item # 59 dalam buku "C ++ Coding Standards" Sutter / Alexandrescu). Perubahan Xeo membantu menghindari mendorong praktik buruk.std::make_shared
bukan hanya singkatan untukstd::shared_ptr<Type> ptr(new Type(...));
. Itu melakukan sesuatu yang tidak bisa Anda lakukan tanpanya.Untuk melakukan tugasnya,
std::shared_ptr
harus mengalokasikan blok pelacak selain menahan penyimpanan untuk penunjuk yang sebenarnya. Namun, karenastd::make_shared
mengalokasikan objek yang sebenarnya, ada kemungkinan bahwastd::make_shared
mengalokasikan objek dan blok pelacakan di blok memori yang sama.Jadi sementara
std::shared_ptr<Type> ptr = new Type(...);
akan ada dua alokasi memori (satu untuknew
, satu distd::shared_ptr
blok pelacakan),std::make_shared<Type>(...)
akan mengalokasikan satu blok memori.Itu penting bagi banyak pengguna potensial
std::shared_ptr
. Satu-satunya hal yangstd::make_unique
akan dilakukan adalah sedikit lebih nyaman. Tidak lebih dari itu.sumber
Sementara tidak ada yang menghentikan Anda dari menulis pembantu Anda sendiri, saya percaya bahwa alasan utama menyediakan
make_shared<T>
di perpustakaan adalah bahwa itu sebenarnya menciptakan jenis internal yang berbeda dari pointer bersamashared_ptr<T>(new T)
, yang dialokasikan secara berbeda, dan tidak ada cara untuk mencapai ini tanpa dedikasi pembantu.Koreksi: ini sebenarnya tidak benar: Memiliki panggilan fungsi untuk membungkusmake_unique
Pembungkus Anda di sisi lain hanyalah gula sintaksis di sekitarnew
ekspresi, jadi meskipun mungkin terlihat menyenangkan bagi mata, itu tidak membawa apa punnew
ke meja.new
ekspresi memberikan keamanan pengecualian, misalnya dalam kasus di mana Anda memanggil suatu fungsivoid f(std::unique_ptr<A> &&, std::unique_ptr<B> &&)
. Memiliki dua mentahnew
yang tidak dilanjutkan sehubungan dengan satu sama lain berarti bahwa jika satu ekspresi baru gagal dengan pengecualian, yang lain dapat membocorkan sumber daya. Adapun mengapa tidak adamake_unique
dalam standar: Itu baru saja dilupakan. (Ini kadang-kadang terjadi. Tidak ada globalstd::cbegin
dalam standar meskipun harus ada satu.)Perhatikan juga bahwa
unique_ptr
mengambil parameter templat kedua yang entah bagaimana harus Anda izinkan; ini berbeda denganshared_ptr
, yang menggunakan penghapusan tipe untuk menyimpan delet khusus tanpa menjadikannya bagian dari tipe itu.sumber
shared_ptr<T>(new T)
menggunakan salah satunya,make_shared<T>()
menggunakan yang berbeda. Membiarkan itu adalah Good Thing, dan versi make-shared dalam beberapa hal adalah pointer bersama paling ringan yang bisa Anda dapatkan.shared_ptr
mengalokasikan blok memori dinamis untuk menjaga jumlah dan aksi "disposer" saat Anda membuat ashared_ptr
. Jika Anda melewati pointer secara eksplisit, perlu menciptakan "baru" blok, jika Anda menggunakanmake_shared
itu dapat bundel Anda objek dan data satelit dalam satu blok memori (satunew
) yang mengakibatkan lebih cepat alokasi / dealokasi, kurang fragmentasi, dan (biasanya ) perilaku cache yang lebih baik.Dalam C ++ 11
...
digunakan (dalam kode templat) untuk "paket ekspansi" juga.Syaratnya adalah Anda menggunakannya sebagai akhiran dari ekspresi yang berisi paket parameter yang tidak dikembangkan, dan itu hanya akan menerapkan ekspresi untuk masing-masing elemen paket.
Misalnya, membangun contoh Anda:
Yang terakhir salah saya pikir.
Juga, paket argumen tidak dapat diteruskan ke fungsi yang tidak dikembangkan. Saya tidak yakin tentang paket parameter template.
sumber
std::forward<Args>(args)...
, yang diperluas keforward<T1>(x1), forward<T2>(x2), ...
.forward
sebenarnya selalu membutuhkan parameter template, bukan?Terinspirasi oleh implementasi oleh Stephan T. Lavavej, saya pikir mungkin lebih baik memiliki make_unique yang mendukung perluasan array, ada di github dan saya ingin mendapatkan komentar tentangnya. Ini memungkinkan Anda untuk melakukan ini:
sumber