std::unique_ptr
memiliki dukungan untuk array, misalnya:
std::unique_ptr<int[]> p(new int[10]);
tetapi apakah itu dibutuhkan? mungkin lebih nyaman digunakan std::vector
atau std::array
.
Apakah Anda menemukan kegunaan untuk konstruksi itu?
std::unique_ptr
memiliki dukungan untuk array, misalnya:
std::unique_ptr<int[]> p(new int[10]);
tetapi apakah itu dibutuhkan? mungkin lebih nyaman digunakan std::vector
atau std::array
.
Apakah Anda menemukan kegunaan untuk konstruksi itu?
std::shared_ptr<T[]>
, tetapi harus ada, dan mungkin akan ada di C ++ 14 jika ada yang bisa repot menulis proposal. Sementara itu, selalu adaboost::shared_array
.std::shared_ptr
<T []> sekarang dalam c ++ 17.Jawaban:
Beberapa orang tidak memiliki kemewahan menggunakan
std::vector
, bahkan dengan pengalokasi. Beberapa orang membutuhkan array berukuran dinamis, begitustd::array
juga keluar. Dan beberapa orang mendapatkan array mereka dari kode lain yang diketahui mengembalikan array; dan kode itu tidak akan ditulis ulang untuk mengembalikanvector
atau sesuatu.Dengan mengizinkan
unique_ptr<T[]>
, Anda melayani kebutuhan itu.Singkatnya, Anda gunakan
unique_ptr<T[]>
saat Anda membutuhkannya . Ketika alternatif tidak akan bekerja untuk Anda. Ini alat pilihan terakhir.sumber
vector
". Anda dapat berdebat apakah persyaratan tersebut masuk akal atau tidak, tetapi Anda tidak dapat menyangkal bahwa persyaratan itu ada .std::vector
jika mereka dapat menggunakannyastd::unique_ptr
.unique_ptr
tetapi proyek-proyek semacam itu benar-benar ada.Ada pengorbanan, dan Anda memilih solusi yang sesuai dengan yang Anda inginkan. Dari atas kepala saya:
Ukuran inisial
vector
danunique_ptr<T[]>
memungkinkan ukurannya ditentukan pada saat run-timearray
hanya memungkinkan ukuran ditentukan pada waktu kompilasiMengubah ukuran
array
danunique_ptr<T[]>
tidak mengizinkan pengubahan ukuranvector
tidakPenyimpanan
vector
danunique_ptr<T[]>
menyimpan data di luar objek (biasanya di heap)array
menyimpan data secara langsung di objekPenyalinan
array
danvector
memungkinkan penyalinanunique_ptr<T[]>
tidak mengizinkan penyalinanTukar / pindahkan
vector
danunique_ptr<T[]>
punya O (1) waktuswap
dan memindahkan operasiarray
memiliki O (n) waktuswap
dan memindahkan operasi, di mana n adalah jumlah elemen dalam arrayPointer / referensi / pembatalan iterator
array
memastikan pointer, referensi dan iterator tidak akan pernah batal ketika objek hidup, bahkan diswap()
unique_ptr<T[]>
tidak memiliki iterator; pointer dan referensi hanya dibatalkan padaswap()
saat objek hidup. (Setelah bertukar, pointer menunjuk ke array yang Anda bertukar, jadi mereka masih "valid" dalam pengertian itu.)vector
dapat membatalkan pointer, referensi dan iterator pada realokasi apa pun (dan memberikan beberapa jaminan bahwa realokasi hanya dapat terjadi pada operasi tertentu).Kompatibilitas dengan konsep dan algoritma
array
danvector
keduanya adalah Wadahunique_ptr<T[]>
bukan sebuah KontainerHarus saya akui, ini sepertinya peluang untuk refactoring dengan desain berbasis kebijakan.
sumber
vector
. Kemudian Anda meningkatkan ukuran atau kapasitasvector
sehingga memaksa realokasi. Kemudian iterator, pointer atau referensi tidak lagi menunjuk ke elemenvector
. Inilah yang kami maksud dengan "invalidation". Masalah ini tidak terjadiarray
, karena tidak ada "realokasi". Sebenarnya, saya hanya memperhatikan detail dengan itu, dan saya sudah mengeditnya sesuai.unique_ptr<T[]>
karena tidak ada realokasi. Tapi tentu saja, ketika array keluar dari cakupan, pointer ke elemen tertentu masih akan batal.T[]
, ukuran (atau informasi yang setara) harus berkeliaran di suatu tempat untukoperator delete[]
menghancurkan elemen array dengan benar. Akan lebih baik jika programmer memiliki akses ke sana.Salah satu alasan Anda mungkin menggunakan a
unique_ptr
adalah jika Anda tidak ingin membayar biaya runtime dari inisialisasi nilai array.The
std::vector
konstruktor danstd::vector::resize()
akan menghargai-initializeT
- tetapinew
tidak akan melakukan itu jikaT
adalah POD.Lihat Nilai-Inisialisasi Objek di C ++ 11 dan std :: vector constructor
Perhatikan bahwa
vector::reserve
ini bukan alternatif di sini: Apakah mengakses pointer mentah setelah std :: vector :: cadangan aman?Itu alasan yang sama yang mungkin dipilih oleh programmer C
malloc
lebihcalloc
.sumber
std::vector
sebuah pengalokasi kustom yang menghindari pembangunan jenis yangstd::is_trivially_default_constructible
dan penghancuran benda-benda yangstd::is_trivially_destructible
, meskipun ketat ini melanggar standar C ++ (karena jenis tersebut tidak default dijalankan).std::unique_ptr
tidak menyediakan pengecekan terikat yang bertentangan dengan banyakstd::vector
implementasi.std::vector
diperlukan oleh Standar untuk memeriksa batasan dalam.at()
. Saya kira Anda maksudkan bahwa beberapa implementasi memiliki mode debug yang akan memeriksa.operator[]
juga, tapi saya menganggap itu tidak berguna untuk menulis kode portabel yang baik.Sebuah
std::vector
dapat disalin sekitar, sambilunique_ptr<int[]>
memungkinkan mengekspresikan kepemilikan unik dari array.std::array
, di sisi lain, membutuhkan ukuran yang harus ditentukan pada waktu kompilasi, yang mungkin tidak mungkin dalam beberapa situasi.sumber
unique_ptr
bukanshared_ptr
. Apakah saya melewatkan sesuatu?unique_ptr
tidak lebih dari sekadar mencegah penyalahgunaan yang tidak disengaja. Ini juga lebih kecil dan overhead yang lebih rendah daripadashared_ptr
. Intinya adalah, walaupun senang memiliki semantik di kelas yang mencegah "penyalahgunaan", itu bukan satu-satunya alasan untuk menggunakan jenis tertentu. Danvector
jauh lebih berguna sebagai penyimpanan array daripadaunique_ptr<T[]>
, jika tanpa alasan selain fakta bahwa ia memiliki ukuran .vector
diunique_ptr<T[]>
mana mungkin, alih-alih hanya mengatakan, "Anda tidak dapat menyalinnya" dan karena itu pilihunique_ptr<T[]>
ketika Anda tidak ingin salinan. Menghentikan seseorang dari melakukan hal yang salah belum tentu merupakan alasan paling penting untuk memilih kelas.std::vector
memiliki lebih banyak overhead daripadastd::unique_ptr
- ia menggunakan ~ 3 pointer bukannya ~ 1.std::unique_ptr
memblokir penyalinan tetapi memungkinkan pemindahan konstruksi, yang jika secara semantik data yang Anda kerjakan hanya dapat dipindahkan tetapi tidak disalin, menginfeksi yangclass
berisi data tersebut. Memiliki operasi pada data yang tidak valid sebenarnya membuat kelas kontainer Anda lebih buruk, dan "jangan gunakan itu" tidak menghapus semua dosa. Harus meletakkan setiap instance dari Andastd::vector
ke dalam kelas di mana Anda menonaktifkan secara manualmove
adalah sakit kepala.std::unique_ptr<std::array>
memiliki asize
.Scott Meyers mengatakan ini dalam C ++ Modern yang Efektif
Saya pikir jawaban Charles Salvia relevan: itu
std::unique_ptr<T[]>
adalah satu-satunya cara untuk menginisialisasi array kosong yang ukurannya tidak diketahui pada waktu kompilasi. Apa yang akan dikatakan Scott Meyers tentang motivasi untuk menggunakan inistd::unique_ptr<T[]>
?sumber
vector
stackoverflow.com/a/24852984/2436175 .Berlawanan dengan
std::vector
danstd::array
,std::unique_ptr
dapat memiliki pointer NULL.Ini berguna saat bekerja dengan API C yang mengharapkan array atau NULL:
sumber
Saya telah terbiasa
unique_ptr<char[]>
mengimplementasikan kumpulan memori yang telah dialokasikan sebelumnya yang digunakan dalam mesin game. Idenya adalah untuk menyediakan kumpulan memori yang telah dialokasikan sebelumnya yang digunakan alih-alih alokasi dinamis untuk mengembalikan hasil permintaan tabrakan dan hal-hal lain seperti fisika partikel tanpa harus mengalokasikan / membebaskan memori pada setiap frame. Ini cukup nyaman untuk skenario semacam ini di mana Anda memerlukan kumpulan memori untuk mengalokasikan objek dengan waktu hidup terbatas (biasanya satu, 2 atau 3 frame) yang tidak memerlukan logika penghancuran (hanya alokasi memori).sumber
Pola umum dapat ditemukan di beberapa panggilan Windows Win32 API , di mana penggunaan
std::unique_ptr<T[]>
bisa berguna, misalnya ketika Anda tidak tahu persis seberapa besar buffer output seharusnya ketika memanggil beberapa Win32 API (yang akan menulis beberapa data di dalam buffer itu):sumber
std::vector<char>
dalam kasus ini.Saya menghadapi kasus di mana saya harus menggunakan
std::unique_ptr<bool[]>
, yang ada di perpustakaan HDF5 (perpustakaan untuk penyimpanan data biner yang efisien, banyak digunakan dalam sains). Beberapa kompiler (Visual Studio 2015 dalam kasus saya) memberikan kompresistd::vector<bool>
(dengan menggunakan 8 bools di setiap byte), yang merupakan bencana untuk sesuatu seperti HDF5, yang tidak peduli dengan kompresi itu. Denganstd::vector<bool>
, HDF5 akhirnya membaca sampah karena kompresi itu.Tebak siapa yang ada di sana untuk penyelamatan, dalam kasus di mana
std::vector
tidak bekerja, dan saya perlu mengalokasikan array dinamis dengan bersih? :-)sumber
Singkatnya: sejauh ini yang paling hemat memori.
A
std::string
dilengkapi dengan pointer, panjang, dan buffer "optimasi string pendek". Tetapi situasi saya adalah saya perlu menyimpan string yang hampir selalu kosong, dalam struktur yang saya miliki ratusan ribu. Dalam C, saya hanya akan menggunakanchar *
, dan itu akan menjadi null sebagian besar waktu. Yang bekerja untuk C ++ juga, kecuali bahwachar *
tidak memiliki destruktor, dan tidak tahu untuk menghapus sendiri. Sebaliknya, astd::unique_ptr<char[]>
akan menghapus sendiri ketika keluar dari ruang lingkup. Yang kosongstd::string
membutuhkan 32 byte, tetapi yang kosongstd::unique_ptr<char[]>
membutuhkan 8 byte, yaitu, persis ukuran penunjuknya.Kelemahan terbesar adalah, setiap kali saya ingin mengetahui panjang tali, saya harus memanggilnya
strlen
.sumber
Untuk menjawab orang-orang yang berpikir Anda "harus" menggunakan,
vector
bukanunique_ptr
saya memiliki kasus dalam pemrograman CUDA pada GPU ketika Anda mengalokasikan memori di Perangkat Anda harus menggunakan array pointer (dengancudaMalloc
). Kemudian, ketika mengambil data ini di Host, Anda harus menggunakan pointer lagi danunique_ptr
dapat menangani pointer dengan mudah. Biaya tambahan konversidouble*
kevector<double>
tidak perlu dan menyebabkan hilangnya kinerja.sumber
Satu alasan tambahan untuk membolehkan dan menggunakan
std::unique_ptr<T[]>
, yang belum disebutkan dalam tanggapan sejauh ini: memungkinkan Anda untuk meneruskan jenis elemen array.Ini berguna ketika Anda ingin meminimalkan rantai
#include
pernyataan di header (untuk mengoptimalkan kinerja pembangunan.)Misalnya -
Dengan struktur kode di atas, siapa pun dapat
#include "myclass.h"
dan menggunakanMyClass
, tanpa harus menyertakan dependensi implementasi internal yang diperlukan olehMyClass::m_InternalArray
.Jika
m_InternalArray
bukan dinyatakan sebagaistd::array<ALargeAndComplicatedClassWithLotsOfDependencies>
, ataustd::vector<...>
, masing-masing - hasilnya akan dicoba penggunaan jenis yang tidak lengkap, yang merupakan kesalahan waktu kompilasi.sumber
class ALargeAndComplicatedClassWithLotsOfDependencies
. Jadi secara logis Anda seharusnya tidak mengalami skenario seperti itu.Saya tidak bisa tidak setuju dengan semangat jawaban yang diterima dengan cukup kuat. "Alat pilihan terakhir"? Jauh dari itu!
Cara saya melihatnya, salah satu fitur terkuat dari C ++ dibandingkan dengan C dan beberapa bahasa lain yang serupa adalah kemampuan untuk mengekspresikan kendala sehingga mereka dapat diperiksa pada waktu kompilasi dan penyalahgunaan yang tidak disengaja dapat dicegah. Jadi, ketika merancang struktur, tanyakan pada diri sendiri operasi apa yang harus diizinkan. Semua penggunaan lain harus dilarang, dan yang terbaik adalah jika pembatasan tersebut dapat diimplementasikan secara statis (pada waktu kompilasi) sehingga penyalahgunaan menyebabkan kegagalan kompilasi.
Jadi ketika seseorang membutuhkan sebuah array, jawaban untuk pertanyaan berikut menentukan perilakunya: 1. Apakah ukurannya a) dinamis saat runtime, atau b) statis, tetapi hanya dikenal saat runtime, atau c) statis dan dikenal pada waktu kompilasi? 2. Dapatkah array dialokasikan pada stack atau tidak?
Dan berdasarkan jawaban, inilah yang saya lihat sebagai struktur data terbaik untuk array seperti itu:
Ya, saya pikir
unique_ptr<std::array>
juga harus dipertimbangkan, dan tidak ada alat terakhir. Coba pikirkan apa yang paling cocok dengan algoritma Anda.Semua ini kompatibel dengan API C sederhana melalui pointer mentah ke array data (
vector.data()
/array.data()
/uniquePtr.get()
).PS Terlepas dari pertimbangan di atas, ada juga satu kepemilikan:
std::array
danstd::vector
memiliki semantik nilai (memiliki dukungan asli untuk menyalin dan melewati nilai), sementaraunique_ptr<T[]>
hanya dapat dipindahkan (menegakkan kepemilikan tunggal). Entah dapat berguna dalam skenario yang berbeda. Sebaliknya, array statis polos (int[N]
) dan array dinamis polos (new int[10]
) tidak menawarkan dan karenanya harus dihindari jika mungkin - yang seharusnya dimungkinkan dalam sebagian besar kasus. Jika itu tidak cukup, array dinamis polos juga tidak menawarkan cara untuk menanyakan ukurannya - peluang tambahan untuk kerusakan memori dan celah keamanan.sumber
Mereka mungkin jawaban yang paling tepat ketika Anda hanya bisa menyodok satu pointer melalui API yang ada (pikirkan jendela pesan atau parameter panggilan balik terkait threading) yang memiliki ukuran seumur hidup setelah "tertangkap" di sisi lain dari palka, tetapi yang tidak terkait dengan kode panggilan:
Kita semua ingin semuanya menyenangkan bagi kita. C ++ untuk waktu lainnya.
sumber
unique_ptr<char[]>
dapat digunakan di mana Anda ingin kinerja C dan kenyamanan C ++. Pertimbangkan Anda perlu beroperasi pada jutaan (ok, miliaran jika Anda belum percaya) dari string. Menyimpan masing-masing dalam objekstring
atau terpisahvector<char>
akan menjadi bencana bagi rutinitas manajemen memori (tumpukan). Terutama jika Anda perlu mengalokasikan dan menghapus string yang berbeda berkali-kali.Namun, Anda dapat mengalokasikan buffer tunggal untuk menyimpan banyak string itu. Anda tidak akan suka
char* buffer = (char*)malloc(total_size);
karena alasan yang jelas (jika tidak jelas, cari "mengapa menggunakan smart ptrs"). Anda lebih sukaunique_ptr<char[]> buffer(new char[total_size]);
Secara analogi, pertimbangan kinerja & kenyamanan yang sama berlaku untuk non-
char
data (pertimbangkan jutaan vektor / matriks / objek).sumber
vector<char>
? Jawabannya, saya kira, adalah karena mereka akan diinisialisasi nol ketika Anda membuat buffer, sedangkan mereka tidak akan menjadi jika Anda menggunakanunique_ptr<char[]>
. Tapi nugget kunci ini hilang dari jawaban Anda.new[]
std::vector
, misalnya, untuk mencegah programmer yang ceroboh memasukkan salinan secara tidak sengajaAda aturan umum bahwa wadah C ++ lebih disukai daripada bergulir sendiri dengan pointer. Ini adalah aturan umum; ini memiliki pengecualian. Masih ada lagi; ini hanya contoh.
sumber
Jika Anda membutuhkan array dinamis dari objek yang tidak dapat dikopi-konstruksikan, maka pointer cerdas ke array adalah cara yang harus dilakukan. Misalnya, bagaimana jika Anda membutuhkan array atom.
sumber