Saya menemukan sebuah kuis yang melibatkan deklarasi array dengan ukuran berbeda. Hal pertama yang terlintas di pikiran saya adalah bahwa saya perlu menggunakan alokasi dinamis dengan new
perintah, seperti ini:
while(T--) {
int N;
cin >> N;
int *array = new int[N];
// Do something with 'array'
delete[] array;
}
Namun, saya melihat bahwa salah satu solusi memungkinkan kasus berikut:
while(T--) {
int N;
cin >> N;
int array[N];
// Do something with 'array'
}
Setelah sedikit riset, saya membaca bahwa g ++ memungkinkan ini, tetapi membuat saya berpikir, dalam hal apa kemudian diperlukan untuk menggunakan alokasi dinamis? Atau apakah kompiler menerjemahkan ini sebagai alokasi dinamis?
Fungsi hapus disertakan. Perhatikan, bagaimanapun, bahwa pertanyaan di sini bukan tentang kebocoran memori.
c++
arrays
dynamic-memory-allocation
static-memory-allocation
learning_dude
sumber
sumber
std::vector
(std::vector<int> array(N);
).new OBJ
secara langsung.Jawaban:
Cuplikan yang Anda tampilkan tidak idiomatis, kode C ++ modern.
new
dandelete
(dannew[]
dandelete[]
) tidak ditinggalkan dalam C ++ dan tidak akan pernah. Mereka masih merupakan cara untuk instantiate objek yang dialokasikan secara dinamis. Namun, karena Anda harus selalu mencocokkan anew
dengandelete
(dan anew[]
dengandelete[]
), mereka paling baik disimpan dalam kelas (perpustakaan) yang memastikan ini untuk Anda. Lihat Mengapa pemrogram C ++ meminimalkan penggunaan 'baru'? .Cuplikan pertama Anda menggunakan "telanjang"
new[]
dan kemudian tidak pernahdelete[]
menciptakan array. Itu masalah.std::vector
melakukan semua yang Anda butuhkan di sini dengan baik. Ini akan menggunakan beberapa bentuk dinew
belakang layar (saya tidak akan membahas rincian implementasi), tetapi untuk semua yang Anda harus peduli, itu adalah array yang dinamis tetapi lebih baik dan lebih aman.Cuplikan kedua Anda menggunakan "array panjang variabel" (VLA), fitur C yang juga diizinkan oleh beberapa kompiler di C ++ sebagai ekstensi. Tidak seperti
new
, VLA pada dasarnya dialokasikan pada stack (sumber daya yang sangat terbatas). Tetapi yang lebih penting, mereka bukan fitur C ++ standar dan harus dihindari karena mereka tidak portabel. Mereka tentu tidak menggantikan alokasi dinamis (yaitu tumpukan).sumber
Qt
, karena kelas dasarnya semuanya memiliki pemulung, jadi Anda cukup sering menggunakannew
dan melupakannya, Untuk elemen GUI, ketika widget orangtua ditutup, anak-anak keluar dari ruang lingkup dan dikumpulkan secara otomatis.new
masih memiliki kecocokandelete
; hanya sajadelete
s dilakukan oleh widget induk daripada di blok kode yang sama dengannew
s.Baiklah, sebagai permulaan,
new
/delete
tidak mendapatkan usang.Dalam kasus spesifik Anda, mereka bukan satu-satunya solusi. Apa yang Anda pilih tergantung pada apa yang disembunyikan di bawah komentar "lakukan sesuatu dengan array" Anda.
Contoh ke-2 Anda menggunakan ekstensi VLA non-standar yang mencoba menyesuaikan array pada stack. Ini memiliki keterbatasan tertentu - yaitu ukuran terbatas dan ketidakmampuan untuk menggunakan memori ini setelah array keluar dari ruang lingkup. Anda tidak dapat memindahkannya, itu akan "menghilang" setelah tumpukan dibuka.
Jadi, jika satu-satunya tujuan Anda adalah melakukan perhitungan lokal dan kemudian membuang data, itu mungkin benar-benar berfungsi dengan baik. Namun, pendekatan yang lebih kuat adalah mengalokasikan memori secara dinamis, lebih disukai dengan
std::vector
. Dengan begitu Anda mendapatkan kemampuan untuk membuat ruang untuk elemen yang persis sama banyaknya seperti yang Anda butuhkan berdasarkan nilai runtime (yang akan kita lakukan selama ini), tetapi juga akan membersihkan dirinya dengan baik, dan Anda dapat memindahkannya ruang lingkup ini jika Anda ingin menyimpan memori digunakan untuk nanti.Berputar kembali ke awal, mungkin
vector
akan menggunakannew
beberapa lapisan lebih dalam, tetapi Anda tidak perlu khawatir dengan itu, karena antarmuka yang dihadirkannya jauh lebih unggul. Dalam hal itu, menggunakannew
dandelete
dapat dianggap tidak dianjurkan.sumber
new
dandelete
, tetapi lebih suka menggunakan smart pointer sepertistd::unique_pointer
.std::unique_ptr
std::unique_ptr
panggilan destruktor defaultdelete
ataudelete[]
, yang berarti bahwa objek yang dimiliki harus dialokasikan olehnew
ataunew[]
, yang panggilan telah disembunyikanstd::make_unique
sejak C ++ 14.Contoh kedua Anda menggunakan array panjang variabel (VLA), yang sebenarnya merupakan fitur C99 ( bukan C ++!), Namun demikian didukung oleh g ++ .
Lihat juga jawaban ini .
Perhatikan bahwa array panjang variabel berbeda dari
new
/delete
dan jangan "mencabut" mereka dengan cara apa pun.Perlu diketahui juga bahwa VLA bukan ISO C ++.
sumber
C ++ modern menyediakan cara yang lebih mudah untuk bekerja dengan alokasi dinamis. Pointer pintar dapat menangani pembersihan setelah pengecualian (yang mungkin terjadi di mana saja jika diizinkan) dan pengembalian awal, segera setelah struktur data yang direferensikan keluar dari ruang lingkup, jadi mungkin masuk akal untuk menggunakan ini sebagai gantinya:
Dari C ++ 14 Anda juga dapat menulis
ini terlihat lebih bagus dan akan mencegah kebocoran memori jika alokasi gagal. Dari C ++ 20 Anda harus dapat melakukan sebanyak mungkin
ini bagi saya masih belum dikompilasi pada saat penulisan dengan gcc 7.4.0. Dalam dua contoh ini kami juga menggunakan
auto
bukan tipe deklarasi di sebelah kiri. Dalam semua kasus, gunakan array seperti biasa:Memori bocor dari
new
dan crash dari dua kali lipatdelete
adalah sesuatu C ++ telah dihancurkan selama bertahun-tahun, menjadi "titik sentral" dari argumentasi untuk beralih ke bahasa lain. Mungkin lebih baik dihindari.sumber
unique/shared_ptr
konstruktor yang mendukungmake_unique/shared
, bukan saja Anda tidak harus menulis tipe yang dikonstruksikan dua kali (menggunakanauto
) tetapi Anda tidak berisiko bocor memori atau sumber daya jika konstruksi gagal sebagian (jika Anda menggunakan tipe yang dapat gagal)make_shared<int[]>
banyak menggunakan , ketika Anda selalu inginvector<int>
, tapi senang mengetahui.unique_ptr
konstruktornya bukanhrow, jadi bagiT
yang memiliki konstruktor nothrow, jadi tidak ada risiko kebocoran denganunique_ptr(new int[size])
danshared_ptr
memiliki yang berikut: "Jika pengecualian dilemparkan, hapus p dipanggil ketika T bukan tipe array, hapus [ ] p sebaliknya. ", jadi Anda memiliki efek yang sama - risikonya adalah untukunique/shared_ptr(new MyPossiblyAllocatingType[size])
.baru dan hapus tidak ditinggalkan.
Objek yang dibuat oleh operator baru dapat dilewatkan dengan referensi. Objek dapat dihapus menggunakan delete.
baru dan hapus adalah aspek dasar bahasa. Kegigihan suatu objek dapat dikelola menggunakan yang baru dan menghapus. Ini pasti tidak akan ditinggalkan.
Statement - int array [N] adalah cara mendefinisikan sebuah array. Array dapat digunakan dalam lingkup blok kode terlampir. Itu tidak bisa dilewati seperti bagaimana suatu objek dilewatkan ke fungsi lain.
sumber
Contoh pertama membutuhkan
delete[]
di akhir, atau Anda akan memiliki kebocoran memori.Contoh kedua menggunakan panjang array variabel yang tidak didukung oleh C ++; itu hanya memungkinkan konstan ekspresi untuk panjang array .
Dalam hal ini berguna untuk digunakan
std::vector<>
sebagai solusi; yang membungkus semua tindakan yang dapat Anda lakukan pada array ke dalam kelas templat.sumber
Sintaksnya terlihat seperti C ++, tetapi idiomnya mirip dengan Algol60 tua biasa. Itu umum untuk memiliki blok kode seperti ini:
Contohnya dapat ditulis sebagai:
Saya terkadang melewatkan ini dalam bahasa saat ini;)
sumber