Ada dua teknik alokasi memori yang banyak digunakan: alokasi otomatis dan alokasi dinamis. Secara umum, ada wilayah memori yang sesuai untuk masing-masing: tumpukan dan tumpukan.
Tumpukan
Tumpukan selalu mengalokasikan memori secara berurutan. Itu dapat melakukannya karena mengharuskan Anda untuk melepaskan memori dalam urutan terbalik (First-In, Last-Out: FILO). Ini adalah teknik alokasi memori untuk variabel lokal dalam banyak bahasa pemrograman. Ini sangat, sangat cepat karena membutuhkan pembukuan minimal dan alamat berikutnya untuk dialokasikan adalah implisit.
Dalam C ++, ini disebut penyimpanan otomatis karena penyimpanan diklaim secara otomatis pada akhir ruang lingkup. Segera setelah eksekusi blok kode saat ini (dibatasi penggunaan {}
) selesai, memori untuk semua variabel di blok itu dikumpulkan secara otomatis. Ini juga merupakan momen di mana para penghancur dipanggil untuk membersihkan sumber daya.
Tumpukan
Tumpukan memungkinkan untuk mode alokasi memori yang lebih fleksibel. Pembukuan lebih kompleks dan alokasi lebih lambat. Karena tidak ada titik rilis implisit, Anda harus melepaskan memori secara manual, menggunakan delete
atau delete[]
(free
dalam C). Namun, tidak adanya titik rilis tersirat adalah kunci untuk fleksibilitas tumpukan.
Alasan menggunakan alokasi dinamis
Bahkan jika menggunakan tumpukan lebih lambat dan berpotensi menyebabkan kebocoran memori atau fragmentasi memori, ada kasus penggunaan yang sangat baik untuk alokasi dinamis, karena kurang terbatas.
Dua alasan utama untuk menggunakan alokasi dinamis:
Anda tidak tahu berapa banyak memori yang Anda butuhkan pada waktu kompilasi. Misalnya, ketika membaca file teks menjadi string, Anda biasanya tidak tahu ukuran file itu, jadi Anda tidak dapat memutuskan berapa banyak memori yang dialokasikan sampai Anda menjalankan program.
Anda ingin mengalokasikan memori yang akan bertahan setelah meninggalkan blok saat ini. Misalnya, Anda mungkin ingin menulis fungsi string readfile(string path)
yang mengembalikan konten file. Dalam hal ini, bahkan jika tumpukan dapat menampung seluruh isi file, Anda tidak dapat kembali dari fungsi dan mempertahankan blok memori yang dialokasikan.
Mengapa alokasi dinamis seringkali tidak perlu
Di C ++ ada konstruksi rapi yang disebut destruktor . Mekanisme ini memungkinkan Anda untuk mengelola sumber daya dengan menyelaraskan masa pakai sumber daya dengan masa pakai variabel. Teknik ini disebut RAII dan merupakan titik pembeda dari C ++. Ini "membungkus" sumber daya menjadi objek. std::string
adalah contoh sempurna. Cuplikan ini:
int main ( int argc, char* argv[] )
{
std::string program(argv[0]);
}
sebenarnya mengalokasikan sejumlah variabel memori. The std::string
objek mengalokasikan memori menggunakan tumpukan dan rilis di destructor. Dalam hal ini, yang Anda lakukan tidak perlu mengelola sumber daya apa pun secara manual dan masih mendapat manfaat dari alokasi memori dinamis.
Secara khusus, ini menyiratkan bahwa dalam cuplikan ini:
int main ( int argc, char* argv[] )
{
std::string * program = new std::string(argv[0]); // Bad!
delete program;
}
ada alokasi memori dinamis yang tidak dibutuhkan. Program ini membutuhkan lebih banyak pengetikan (!) Dan memperkenalkan risiko lupa untuk membatalkan alokasi memori. Ini melakukan ini tanpa manfaat nyata.
Mengapa Anda harus menggunakan penyimpanan otomatis sesering mungkin
Pada dasarnya, paragraf terakhir merangkumnya. Menggunakan penyimpanan otomatis sesering mungkin membuat program Anda:
- lebih cepat mengetik;
- lebih cepat saat dijalankan;
- kurang rentan terhadap kebocoran memori / sumber daya.
Poin bonus
Dalam pertanyaan yang dirujuk, ada kekhawatiran tambahan. Secara khusus, kelas berikut:
class Line {
public:
Line();
~Line();
std::string* mString;
};
Line::Line() {
mString = new std::string("foo_bar");
}
Line::~Line() {
delete mString;
}
Sebenarnya jauh lebih berisiko untuk digunakan daripada yang berikut:
class Line {
public:
Line();
std::string mString;
};
Line::Line() {
mString = "foo_bar";
// note: there is a cleaner way to write this.
}
Alasannya adalah bahwa std::string
mendefinisikan konstruktor salinan dengan benar. Pertimbangkan program berikut:
int main ()
{
Line l1;
Line l2 = l1;
}
Menggunakan versi asli, program ini kemungkinan akan macet, karena digunakan delete
pada string yang sama dua kali. Menggunakan versi yang dimodifikasi, setiap Line
instance akan memiliki instance string sendiri , masing-masing dengan ingatannya sendiri dan keduanya akan dirilis pada akhir program.
Catatan lain
Penggunaan ekstensif RAII dianggap sebagai praktik terbaik dalam C ++ karena semua alasan di atas. Namun, ada manfaat tambahan yang tidak segera terlihat. Pada dasarnya, ini lebih baik daripada jumlah bagian-bagiannya. Seluruh mekanisme terbentuk . Itu bersisik.
Jika Anda menggunakan Line
kelas sebagai blok penyusun :
class Table
{
Line borders[4];
};
Kemudian
int main ()
{
Table table;
}
mengalokasikan empat std::string
instance, empat Line
instance, satu Table
instance dan semua konten string dan semuanya dibebaskan secara otomatis .
Monster
meludah keluarTreasure
keWorld
ketika mati. DalamDie()
metodenya itu menambah harta ke dunia. Itu harus digunakanworld->Add(new Treasure(/*...*/))
di lain untuk melestarikan harta setelah mati. Alternatifnya adalahshared_ptr
(mungkin berlebihan),auto_ptr
(semantik yang buruk untuk pengalihan kepemilikan), melewati nilai (boros) danmove
+unique_ptr
(belum diimplementasikan secara luas).Karena tumpukan lebih cepat dan anti bocor
Dalam C ++, hanya diperlukan satu instruksi untuk mengalokasikan ruang - pada stack - untuk setiap objek lingkup lokal dalam fungsi yang diberikan, dan tidak mungkin untuk membocorkan salah satu dari memori itu. Komentar itu dimaksudkan (atau seharusnya dimaksudkan) untuk mengatakan sesuatu seperti "gunakan tumpukan dan bukan tumpukan".
sumber
int x; return &x;
Alasannya rumit.
Pertama, C ++ bukan sampah yang dikumpulkan. Karena itu, untuk setiap yang baru, harus ada penghapusan yang sesuai. Jika Anda gagal untuk menghapus ini, maka Anda memiliki kebocoran memori. Sekarang, untuk kasus sederhana seperti ini:
Ini sederhana. Tetapi apa yang terjadi jika "Do stuff" memberikan pengecualian? Ups: kebocoran memori. Apa yang terjadi jika masalah "Lakukan"
return
lebih awal? Ups: kebocoran memori.Dan ini untuk kasus yang paling sederhana . Jika Anda mengembalikan string itu kepada seseorang, sekarang mereka harus menghapusnya. Dan jika mereka melewatinya sebagai argumen, apakah orang yang menerimanya perlu menghapusnya? Kapan mereka harus menghapusnya?
Atau, Anda bisa melakukan ini:
Tidak ada
delete
. Objek dibuat pada "tumpukan", dan itu akan dihancurkan begitu keluar dari ruang lingkup. Anda bahkan dapat mengembalikan objek, sehingga mentransfer kontennya ke fungsi panggilan. Anda dapat meneruskan objek ke fungsi (biasanya sebagai referensi atau referensi-konstan:.void SomeFunc(std::string &iCanModifyThis, const std::string &iCantModifyThis)
Dan sebagainya.Semua tanpa
new
dandelete
. Tidak ada pertanyaan tentang siapa yang memiliki memori atau siapa yang bertanggung jawab untuk menghapusnya. Jika kamu melakukan:Hal ini dimengerti bahwa
otherString
memiliki salinan data yang darisomeString
. Itu bukan pointer; itu adalah objek yang terpisah. Mereka mungkin memiliki konten yang sama, tetapi Anda dapat mengubahnya tanpa mempengaruhi yang lain:Lihat idenya?
sumber
main()
, ada selama durasi program, tidak dapat dengan mudah dibuat pada tumpukan karena situasi, dan petunjuk ke sana diteruskan ke fungsi apa pun yang memerlukan akses ke sana. , dapatkah ini menyebabkan kebocoran jika terjadi crash pada program, atau apakah aman? Saya akan berasumsi yang terakhir, karena OS yang mendelokasi semua memori program harus secara logis mendelokasinya juga, tetapi saya tidak ingin menganggap apa pun ketika datang kenew
.Objek yang dibuat
new
harus pada akhirnyadelete
jangan sampai bocor. Destruktor tidak akan dipanggil, memori tidak akan dibebaskan, semuanya. Karena C ++ tidak memiliki pengumpulan sampah, itu masalah.Objek yang dibuat oleh nilai (yaitu pada stack) secara otomatis mati ketika mereka keluar dari ruang lingkup. Panggilan destruktor dimasukkan oleh kompiler, dan memori dibebaskan secara otomatis saat fungsi kembali.
Pointer pintar suka
unique_ptr
,shared_ptr
memecahkan masalah referensi yang menggantung, tetapi mereka membutuhkan disiplin koding dan memiliki masalah potensial lainnya (copyability, loop referensi, dll.).Juga, dalam skenario multithreaded,
new
adalah titik pertikaian antara thread; mungkin ada dampak kinerja karena terlalu banyak menggunakannew
. Pembuatan objek tumpukan adalah menurut definisi thread-lokal, karena masing-masing thread memiliki tumpukan sendiri.Kelemahan dari objek nilai adalah bahwa mereka mati begitu fungsi host kembali - Anda tidak dapat memberikan referensi kepada mereka kembali ke pemanggil, hanya dengan menyalin, mengembalikan atau bergerak berdasarkan nilai.
sumber
new
harus pada akhirnyadelete
jangan sampai bocor." - lebih buruk lagi,new[]
harus dicocokkan dengandelete[]
, dan Anda mendapatkan perilaku yang tidak terdefinisi jika Andadelete
new[]
-ed memori ataudelete[]
new
-ed memori - sangat sedikit kompiler memperingatkan tentang ini (beberapa alat seperti Cppcheck lakukan ketika mereka bisa).sumber
malloc()
atau teman-temannya untuk mengalokasikan memori yang diperlukan. Namun, tumpukan tidak dapat melepaskan item apa pun di dalam tumpukan, satu-satunya cara tumpukan memori dilepaskan dari atas tumpukan.Saya melihat bahwa beberapa alasan penting untuk melakukan hal baru sesedikit mungkin terlewatkan:
Operator
new
memiliki waktu pelaksanaan non-deterministikMemanggil
new
mungkin atau mungkin tidak menyebabkan OS mengalokasikan halaman fisik baru untuk proses Anda, ini bisa sangat lambat jika Anda sering melakukannya. Atau mungkin sudah memiliki lokasi memori yang sesuai, kita tidak tahu. Jika program Anda perlu memiliki waktu eksekusi yang konsisten dan dapat diprediksi (seperti dalam sistem waktu nyata atau simulasi permainan / fisika), Anda perlu menghindarinew
dalam putaran kritis waktu Anda.Operator
new
adalah sinkronisasi utas implisitYa, Anda mendengar saya, OS Anda perlu memastikan tabel halaman Anda konsisten dan dengan panggilan seperti itu
new
akan menyebabkan utas Anda mendapatkan kunci mutex implisit. Jika Anda secara konsisten meneleponnew
dari banyak utas Anda sebenarnya membuat serial utas Anda (Saya sudah melakukan ini dengan 32 CPU, masing-masing menekannew
untuk mendapatkan beberapa ratus byte masing-masing, aduh! Itu adalah pita royal untuk debug)Selebihnya seperti lambat, fragmentasi, rawan kesalahan, dll telah disebutkan oleh jawaban lain.
sumber
void * someAddress = ...; delete (T*)someAddress
mlock()
atau yang serupa. Ini karena sistem mungkin kehabisan memori dan tidak ada halaman memori fisik siap tersedia untuk stack sehingga OS mungkin perlu menukar atau menulis beberapa cache (menghapus memori kotor) ke disk sebelum eksekusi dapat dilanjutkan.Pra-C ++ 17:
Karena itu rentan terhadap kebocoran halus bahkan jika Anda membungkus hasilnya dengan smart pointer .
Pertimbangkan pengguna "hati-hati" yang ingat untuk membungkus objek dalam pointer pintar:
Kode ini berbahaya karena tidak ada jaminan yang
shared_ptr
dibangun sebelumT1
atau sesudahnyaT2
. Oleh karena itu, jika salah satunew T1()
ataunew T2()
gagal setelah yang lain berhasil, maka objek pertama akan bocor karena tidakshared_ptr
ada untuk menghancurkan dan membatalkan alokasi itu.Solusi: gunakan
make_shared
.Post-C ++ 17:
Ini bukan lagi masalah: C ++ 17 memberikan batasan pada urutan operasi ini, dalam hal ini memastikan bahwa setiap panggilannew()
harus segera diikuti oleh pembangunan smart pointer yang sesuai, tanpa operasi lain di antaranya. Ini menyiratkan bahwa, pada saat yang keduanew()
disebut, dijamin bahwa objek pertama telah dibungkus dengan smart pointer, sehingga mencegah kebocoran jika terjadi pengecualian.Penjelasan lebih rinci dari urutan evaluasi baru yang diperkenalkan oleh C ++ 17 diberikan oleh Barry dalam jawaban lain .Terima kasih kepada @Remy Lebeau untuk menunjukkan bahwa ini masih menjadi masalah di bawah C ++ 17 (meskipun kurang begitu):
shared_ptr
konstruktor dapat gagal mengalokasikan blok kontrol dan melemparnya, dalam hal ini penunjuk yang diteruskan ke sana tidak dihapus.Solusi: gunakan
make_shared
.sumber
new
berhasil dan kemudianshared_ptr
konstruksi berikutnya gagal.std::make_shared()
akan menyelesaikannya jugashared_ptr
konstruktor yang dimaksud mengalokasikan memori untuk blok kontrol yang menyimpan pointer dan deleter yang dibagikan, jadi ya, secara teoritis dapat melempar kesalahan memori. Hanya salin, pindahkan, dan aliasing konstruktor yang tidak membuang.make_shared
mengalokasikan objek yang dibagikan di dalam blok kontrol itu sendiri, jadi hanya ada 1 alokasi alih-alih 2.Untuk sebagian besar, itu seseorang mengangkat kelemahan mereka sendiri ke aturan umum. Tidak ada yang salah per se dengan membuat objek menggunakan
new
operator. Apa yang ada beberapa argumen untuk itu adalah bahwa Anda harus melakukannya dengan beberapa disiplin: jika Anda membuat objek Anda perlu memastikan itu akan dihancurkan.Cara termudah untuk melakukannya adalah dengan membuat objek dalam penyimpanan otomatis, jadi C ++ tahu untuk menghancurkannya ketika keluar dari ruang lingkup:
Sekarang, perhatikan bahwa ketika Anda jatuh blok itu setelah penjepit-akhir,
foo
berada di luar jangkauan. C ++ akan memanggil dtornya secara otomatis untuk Anda. Tidak seperti Java, Anda tidak perlu menunggu sampai GC menemukannya.Anda sudah menulis
Anda ingin mencocokkannya secara eksplisit dengan
atau bahkan lebih baik, alokasikan
File *
sebagai "penunjuk pintar". Jika Anda tidak berhati-hati tentang hal itu dapat menyebabkan kebocoran.Jawabannya sendiri membuat asumsi yang keliru bahwa jika Anda tidak menggunakan
new
Anda tidak mengalokasikan pada tumpukan; sebenarnya, di C ++ Anda tidak tahu itu. Paling-paling, Anda tahu bahwa sedikit kehabisan memori, katakan satu pointer, tentu dialokasikan pada stack. Namun, pertimbangkan apakah implementasi File itu sepertimaka
FileImpl
akan masih dialokasikan pada stack.Dan ya, Anda sebaiknya yakin
di kelas juga; tanpanya, Anda akan membocorkan memori dari heap bahkan jika Anda tampaknya tidak mengalokasikan pada heap sama sekali.
sumber
new
per se , tetapi jika Anda melihat kode asli komentar yangnew
dimaksud , sedang disalahgunakan. Kode ditulis seperti itu Java atau C #, di mananew
digunakan untuk hampir setiap variabel, ketika hal-hal lebih masuk akal untuk berada di tumpukan.new
. Dikatakan bahwa jika Anda memiliki pilihan antara alokasi dinamis dan penyimpanan otomatis, gunakan penyimpanan otomatis.new
, tetapi jika Anda menggunakannyadelete
, Anda salah melakukannya!new()
seharusnya tidak digunakan sesedikit mungkin. Ini harus digunakan secermat mungkin. Dan itu harus digunakan sesering yang diperlukan seperti yang ditentukan oleh pragmatisme.Alokasi objek pada tumpukan, bergantung pada penghancuran implisit mereka, adalah model sederhana. Jika lingkup objek yang diperlukan cocok dengan model itu, maka tidak perlu digunakan
new()
, dengan terkaitdelete()
dan memeriksa pointer NULL. Dalam kasus di mana Anda memiliki banyak alokasi objek berumur pendek di tumpukan harus mengurangi masalah fragmentasi tumpukan.Namun, jika masa hidup objek Anda perlu melampaui ruang lingkup saat
new()
ini maka itu adalah jawaban yang tepat. Pastikan Anda memperhatikan kapan dan bagaimana Anda menelepondelete()
dan kemungkinan pointer NULL, menggunakan objek yang dihapus dan semua gotcha lainnya yang datang dengan penggunaan pointer.sumber
const
ref atau pointer ...?make_shared/_unique
dapat digunakan) callee tidak perlunew
ataudelete
. Jawaban ini meleset dari poin sebenarnya: (A) C ++ menyediakan hal-hal seperti RVO, memindahkan semantik, dan parameter keluaran - yang sering berarti bahwa menangani pembuatan objek dan ekstensi seumur hidup dengan mengembalikan memori yang dialokasikan secara dinamis menjadi tidak perlu dan ceroboh. (B) Bahkan dalam situasi di mana alokasi dinamis diperlukan, stdlib menyediakan pembungkus RAII yang membebaskan pengguna dari detail bagian dalam yang jelek.Saat Anda menggunakan yang baru, objek dialokasikan ke heap. Ini umumnya digunakan ketika Anda mengantisipasi ekspansi. Saat Anda mendeklarasikan objek seperti,
ditempatkan di tumpukan.
Anda harus selalu memanggil destroy pada objek yang Anda tempatkan di heap dengan yang baru. Ini membuka potensi kebocoran memori. Objek yang ditempatkan pada tumpukan tidak rentan terhadap kebocoran memori!
sumber
std::string
ataustd::map
, ya, wawasan yang tajam. Reaksi awal saya adalah "tetapi juga sangat umum untuk memisahkan seumur hidup suatu objek dari ruang lingkup pembuatan kode", tetapi benar-benar kembali dengan nilai atau menerima nilai-nilai lingkup penelepon dengan non-const
referensi atau pointer lebih baik untuk itu, kecuali ketika ada "ekspansi" yang terlibat terlalu. Ada beberapa kegunaan suara lainnya seperti metode pabrik ....Salah satu alasan penting untuk menghindari terlalu banyak tumpukan adalah untuk kinerja - khususnya yang melibatkan kinerja mekanisme manajemen memori default yang digunakan oleh C ++. Sementara alokasi bisa sangat cepat dalam kasus sepele, melakukan banyak
new
dandelete
pada objek ukuran yang tidak seragam tanpa perintah lead yang ketat tidak hanya untuk fragmentasi memori, tetapi juga mempersulit algoritma alokasi dan benar-benar dapat menghancurkan kinerja dalam kasus-kasus tertentu.Itulah masalah yang dikumpulkan oleh memori yang dibuat untuk diselesaikan, memungkinkan untuk mengurangi kerugian yang melekat pada implementasi tumpukan tradisional, sementara masih memungkinkan Anda untuk menggunakan tumpukan tersebut seperlunya.
Namun, lebih baik tetap menghindari masalah itu sama sekali. Jika Anda bisa meletakkannya di tumpukan, maka lakukanlah.
sumber
Saya pikir poster itu dimaksudkan untuk mengatakan
You do not have to allocate everything on the
heap
daripada yangstack
.Pada dasarnya objek dialokasikan pada stack (jika ukuran objek memungkinkan, tentu saja) karena biaya alokasi stack yang murah, daripada alokasi berbasis heap yang melibatkan beberapa pekerjaan oleh pengalokasi, dan menambahkan verbositas karena Anda harus mengelola data yang dialokasikan pada heap.
sumber
Saya cenderung tidak setuju dengan gagasan menggunakan "terlalu banyak" baru. Padahal penggunaan poster asli baru dengan kelas sistem agak konyol. (
int *i; i = new int[9999];
? Benarkah?int i[9999];
Jauh lebih jelas.) Saya pikir itulah yang mendapatkan kambing komentator.Ketika Anda bekerja dengan objek sistem, itu sangat jarang Anda membutuhkan lebih dari satu referensi ke objek yang sama persis. Selama nilainya sama, hanya itu yang penting. Dan objek sistem biasanya tidak memakan banyak ruang dalam memori. (satu byte per karakter, dalam sebuah string). Dan jika mereka melakukannya, perpustakaan harus dirancang untuk memperhitungkan manajemen memori tersebut (jika ditulis dengan baik). Dalam kasus ini, (semua kecuali satu atau dua berita dalam kodenya), yang baru praktis tidak ada gunanya dan hanya berfungsi untuk menimbulkan kebingungan dan potensi bug.
Namun, ketika Anda bekerja dengan kelas / objek Anda sendiri (misalnya kelas Line dari poster asli), maka Anda harus mulai memikirkan masalah-masalah seperti jejak memori, ketekunan data, dll. Sendiri. Pada titik ini, memungkinkan beberapa referensi ke nilai yang sama sangat berharga - memungkinkan konstruksi seperti daftar tertaut, kamus, dan grafik, di mana beberapa variabel perlu tidak hanya memiliki nilai yang sama, tetapi referensi objek yang sama persis di memori. Namun, kelas Line tidak memiliki persyaratan tersebut. Jadi kode poster asli sebenarnya sama sekali tidak perlu
new
.sumber
When you're working with your own classes/objects
... Anda sering tidak punya alasan untuk melakukannya! Sebagian kecil dari Qs ada pada rincian desain wadah oleh coders terampil. Sebaliknya, proporsi yang menyedihkan adalah tentang kebingungan para pemula yang tidak tahu stdlib ada - atau secara aktif diberikan tugas yang mengerikan di 'program' 'kursus', di mana seorang tutor menuntut mereka tanpa sengaja menemukan kembali roda - sebelum mereka bahkan telah belajar apa itu roda dan mengapa itu bekerja. Dengan mempromosikan alokasi yang lebih abstrak, C ++ dapat menyelamatkan kita dari 'segfault dengan daftar tertaut' C yang tak ada habisnya; tolong, mari kita biarkan .int *i; i = new int[9999];
? Benarkah?int i[9999];
Jauh lebih jelas.)" Ya, itu lebih jelas, tetapi untuk bermain sebagai pendukung iblis, tipe itu tidak selalu merupakan argumen yang buruk. Dengan 9999 elemen, saya bisa membayangkan sistem tertanam yang ketat tidak memiliki cukup tumpukan untuk 9999 elemen: 9999x4 byte adalah ~ 40 kB, x8 ~ 80 kB. Jadi, sistem seperti itu mungkin perlu menggunakan alokasi dinamis, dengan asumsi mereka menerapkannya menggunakan memori alternatif. Namun, itu hanya mungkin dapat membenarkan alokasi dinamis, bukannew
; avector
akan menjadi perbaikan nyata dalam kasus itustd::make_unique<int[]>()
tentu saja).Dua alasan:
delete
nanti, atau itu akan menyebabkan kebocoran memori.sumber
new
adalah yang barugoto
.Ingat mengapa
goto
begitu dicerca: sementara itu adalah alat yang kuat, tingkat rendah untuk kontrol aliran, orang sering menggunakannya dengan cara rumit yang tidak perlu yang membuat kode sulit untuk diikuti. Selain itu, pola yang paling berguna dan termudah untuk dibaca dikodekan dalam pernyataan pemrograman terstruktur (misalnyafor
atauwhile
); efek utamanya adalah bahwa kode di managoto
cara yang tepat untuk melakukannya agak jarang, jika Anda tergoda untuk menulisgoto
, Anda mungkin melakukan hal-hal buruk (kecuali Anda benar-benar - tahu apa yang Anda lakukan).new
serupa - sering digunakan untuk membuat hal-hal yang tidak perlu rumit dan sulit untuk dibaca, dan pola penggunaan yang paling berguna dapat dikodekan telah dikodekan ke dalam berbagai kelas. Selain itu, jika Anda perlu menggunakan pola penggunaan baru yang belum ada kelas standar, Anda dapat menulis kelas Anda sendiri yang menyandikannya!Aku bahkan akan berpendapat bahwa
new
adalah lebih buruk daripadagoto
, karena kebutuhan untuk pasangannew
dandelete
pernyataan.Seperti
goto
, jika Anda pernah berpikir perlu menggunakannew
, Anda mungkin melakukan hal-hal buruk - terutama jika Anda melakukannya di luar implementasi kelas yang tujuannya dalam hidup adalah untuk merangkum alokasi dinamis apa pun yang perlu Anda lakukan.sumber
Alasan intinya adalah bahwa objek pada heap selalu sulit digunakan dan dikelola daripada nilai-nilai sederhana. Menulis kode yang mudah dibaca dan dipelihara selalu menjadi prioritas pertama dari setiap programmer yang serius.
Skenario lain adalah perpustakaan yang kami gunakan memberikan semantik nilai dan membuat alokasi dinamis tidak perlu.
Std::string
adalah contoh yang bagus.Namun untuk kode berorientasi objek, menggunakan pointer - yang berarti digunakan
new
untuk membuatnya sebelumnya - adalah suatu keharusan. Untuk menyederhanakan kompleksitas manajemen sumber daya, kami memiliki lusinan alat untuk membuatnya sesederhana mungkin, seperti smart pointer. Paradigma berbasis objek atau paradigma generik mengasumsikan nilai semantik dan membutuhkan lebih sedikit atau tidaknew
sama sekali, seperti yang dinyatakan poster di tempat lain.Pola desain tradisional, terutama yang disebutkan dalam buku GoF , menggunakan
new
banyak, karena mereka adalah kode OO khas.sumber
For object oriented code, using a pointer [...] is a must
: Omong kosong . Jika Anda mendevaluasi 'OO' dengan merujuk hanya ke sebagian kecil, polimorfisme - juga omong kosong: referensi juga berfungsi.[pointer] means use new to create it beforehand
: terutama omong kosong : referensi atau petunjuk dapat diambil untuk objek yang dialokasikan secara otomatis & digunakan secara polimorfik; awasi aku .[typical OO code] use new a lot
: mungkin di beberapa buku lama, tapi siapa yang peduli? C ++ eschewsnew
/ pointer mentah yang samar-samar modern sedapat mungkin - & sama sekali tidak kurang OO dengan melakukannyaSatu poin lagi untuk semua jawaban yang benar di atas, itu tergantung pada jenis pemrograman yang Anda lakukan. Kernel berkembang di Windows misalnya -> Stack sangat terbatas dan Anda mungkin tidak dapat mengambil kesalahan halaman seperti dalam mode pengguna.
Dalam lingkungan seperti itu, panggilan API baru atau mirip C lebih disukai dan bahkan diperlukan.
Tentu saja, ini hanyalah pengecualian dari aturan.
sumber
new
mengalokasikan objek di heap. Jika tidak, objek dialokasikan pada tumpukan. Lihatlah perbedaan antara keduanya .sumber