Penggunaan tumpukan dan tumpukan yang benar dalam C ++?

Saya telah pemrograman untuk beberapa waktu, tetapi kebanyakan Java dan C #. Saya tidak pernah mengatur memori sendiri. Saya baru-baru ini memulai pemrograman C ++, dan saya agak bingung ketika saya harus menyimpan beberapa hal di stack dan kapan harus menyimpannya.

Pemahaman saya adalah bahwa variabel yang diakses sangat sering harus disimpan di stack dan objek, variabel yang jarang digunakan, dan struktur data yang besar harus disimpan di heap. Apakah ini benar atau saya salah?

120
01 марта '09 в 8:32 2009-03-01 08:32 Alexander diatur pada 01 Maret 2009 di 8:32 2009-03-01 08:32
@ 10 jawaban

Tidak, perbedaan antara tumpukan dan tumpukan bukanlah kinerja. Seumur hidup: Setiap variabel lokal di dalam suatu fungsi (semua yang bukan malloc () atau baru) hidup di stack. Hi>

 class Thingy; Thingy* foo( ) { int a; // this int lives on the stack Thingy B; // this thingy lives on the stack and will be deleted when we return from foo Thingy *pointerToB =  // this points to an address on the stack Thingy *pointerToC = new Thingy(); // this makes a Thingy on the heap. // pointerToC contains its address. // this is safe: C lives on the heap and outlives foo(). // Whoever you pass this to must remember to delete it! return pointerToC; // this is NOT SAFE: B lives on the stack and will be deleted when foo() returns. // whoever uses this returned pointer will probably cause a crash! return pointerToB; } 

Untuk pemahaman yang lebih jelas tentang apa tumpukan itu, datanglah ke sana dari ujung yang lain - alih-alih mencoba memahami apa yang tumpukan lakukan dalam hal bahasa tingkat tinggi, cari "tumpukan panggilan" dan "panggilan", dan lihat apa sebenarnya mesin itu. lakukan saat Anda memanggil suatu fungsi. Memori komputer hanyalah serangkaian alamat; heap and stack adalah penemuan dari compiler.

238
01 марта '09 в 8:47 2009-03-01 08:47 jawabannya diberikan oleh Crashworks 01 Maret 09 di 8:47 2009-03-01 08:47

Saya akan mengatakan:

Simpan di tumpukan jika Anda BISA.

Simpan dalam tumpukan jika Anda MEMBUTUHKAN.

Oleh karena itu, lebih memilih tumpukan tumpukan. Beberapa kemungkinan alasan mengapa Anda tidak dapat menyimpan sesuatu di tumpukan adalah sebagai berikut:

  • Itu terlalu besar - untuk program multi-ulir pada OS 32-bit, stack memiliki ukuran kecil dan tetap (setidaknya, waktu pembuatan streaming) (sebagai aturan, hanya beberapa megabyte. Ini berarti bahwa Anda dapat membuat beberapa utas tanpa melelahkan ruang alamat. Untuk Program 64-bit atau program single-threaded (Linux toh) bukan masalah serius, dalam program 32-bit Linux single-threaded biasanya menggunakan tumpukan dinamis yang dapat terus tumbuh sampai mencapai bagian atas tumpukan.
  • Anda perlu mengaksesnya di luar tumpukan sumber - ini benar-benar alasan utama.

Dimungkinkan, dengan kompiler yang masuk akal, untuk mengalokasikan objek dengan ukuran tidak tetap pada heap (biasanya array yang ukurannya tidak diketahui pada waktu kompilasi).

40
01 марта '09 в 11:11 2009-03-01 11:11 jawabannya diberikan oleh MarkR pada 01 Maret 2009 di 11:11 2009-03-01 11:11

Ini lebih halus daripada jawaban lainnya. Tidak ada kesenjangan mutlak antara data dalam tumpukan dan data di tumpukan, berdasarkan cara Anda mendeklarasikannya. Sebagai contoh:

 std::vector<int> v(10); 

Dalam tubuh fungsi yang menyatakan vector (array dinamis) dari sepuluh bi>vector tidak ada di tumpukan.

Dan, tetapi (menurut jawaban lain), masa penyimpanan repositori ini dibatasi oleh masa pakai vector itu sendiri, yang didasarkan pada tumpukan di sini, jadi tidak masalah bagaimana itu diterapkan - kita hanya dapat menganggapnya sebagai objek berbasis stack dengan nilai semantik.

Tidak seperti itu Misalkan fungsinya adalah:

 void GetSomeNumbers(std::vector<int>  { std::vector<int> v(10); // fill v with numbers result.swap(v); } 

Dengan demikian, sesuatu dengan fungsi swap (dan segala jenis nilai kompleks harus memilikinya) dapat berfungsi sebagai semacam referensi yang dapat ditulis u>

Oleh karena itu, pendekatan C ++ modern tidak pernah menyimpan alamat data tumpukan dalam variabel telanjang dari pointer lokal. Semua distribusi tumpukan harus disembunyikan di dalam kelas.

Jika Anda melakukan ini, Anda bisa memikirkan semua variabel dalam program Anda seolah-olah mereka adalah tipe nilai sederhana, dan lupakan heap sama sekali (kecuali ketika Anda menulis kelas kelas wrapper baru untuk beberapa data tumpukan yang seharusnya tidak biasa).

Anda hanya perlu menyimpan sedikit pengetahuan khusus yang akan membantu Anda mengoptimalkan: jika memungkinkan, alih-alih menetapkan satu variabel ke yang lain:

 a = b; 

ganti mereka sebagai berikut:

 a.swap(b); 

karena jauh lebih cepat dan tidak menghasilkan pengecualian. Satu-satunya persyaratan adalah bahwa Anda tidak perlu b untuk terus memegang nilai yang sama (sebagai gantinya, itu akan mendapatkan nilai a , yang akan dibagi menjadi a = b ).

Kerugiannya adalah bahwa pendekatan ini memaksa Anda untuk mengembalikan nilai dari fungsi melalui parameter output alih-alih nilai balik yang sebenarnya. Tapi mereka memperbaikinya di C ++ 0x dari tautan nilai .

Dalam situasi yang paling sulit, Anda akan membawa ide ini ke ekstrem bersama dan menggunakan kelas pointer cerdas, seperti shared_ptr , yang sudah ada di tr1. (Meskipun saya akan mengatakan bahwa jika menurut Anda, Anda mungkin telah melampaui sweet spot standar C ++ penerapan.)

24
01 марта '09 в 12:56 2009-03-01 12:56 jawabannya diberikan oleh Daniel Earwicker 01 Maret 2009 di 12:56 2009-03-01 12:56

Anda juga akan menyimpan item di heap jika itu akan digunakan di luar ruang lingkup fungsi di mana ia dibuat. Satu idiom yang digunakan dengan objek stack disebut RAII - ini termasuk menggunakan objek berbasis stack sebagai pembungkus untuk sumber daya, ketika suatu objek dihancurkan, sumber daya akan dihapus. Objek berbasis tumpukan lebih mudah dilacak ketika Anda bisa melempar pengecualian - Anda tidak perlu khawatir menghapus objek dengan tumpukan di handler pengecualian. Inilah sebabnya mengapa pointer mentah tidak umum digunakan dalam C ++ modern, Anda akan menggunakan pointer cerdas, yang bisa menjadi pembungkus berbasis tumpukan untuk pointer mentah ke objek dengan tumpukan.

6
01 марта '09 в 8:49 2009-03-01 08:49 jawabannya diberikan 1800 INFORMASI 01 Maret 09 di 8:49 2009-03-01 08:49

Untuk menambah jawaban lain, ini mungkin juga terkait dengan kinerja, setidaknya sedikit. Bukan berarti Anda khawatir tentang ini, jika ini tidak berlaku untuk Anda, tetapi:

Alokasi tumpukan memerlukan pencarian blok pelacakan memori yang bukan merupakan operasi waktu yang konstan (dan membutuhkan beberapa siklus dan overhead). Ini mungkin melambat karena fragmentasi memori dan / atau Anda mendekati penggunaan 100% ruang alamat Anda. Di sisi lain, alokasi stack adalah operasi permanen, sebagian besar "gratis".

Satu hal yang perlu dipertimbangkan (sekali lagi, benar-benar hanya penting jika itu menjadi masalah) adalah bahwa ukuran tumpukan biasanya diperbaiki dan bisa jauh lebih kecil daripada ukuran tumpukan. Oleh karena itu, jika Anda memilih objek besar atau banyak objek kecil, Anda mungkin ingin menggunakan banyak; jika Anda kehabisan ruang tumpukan, runtime akan memunculkan pengecualian untuk situs. Ini biasanya bukan masalah besar, tetapi satu hal lagi yang perlu dipertimbangkan.

5
01 марта '09 в 10:46 2009-03-01 10:46 jawabannya diberikan Nick 01 Maret 2009 di 10:46 2009-03-01 10:46

Tumpukan lebih efisien dan lebih mudah dikelola oleh area data.

Tetapi heap harus digunakan untuk sesuatu yang lebih besar dari beberapa kilobyte (ini mudah di C ++, cukup buat boost::scoped_ptr pada stack untuk menahan pointer ke memori yang dialokasikan).

Pertimbangkan algoritma rekursif yang terus menyebut dirinya. Sangat sulit untuk membatasi dan menebak keseluruhan penggunaan tumpukan! Jika pengalokasian tumpukan ( malloc() atau new ) dapat menunjuk ke memori tidak aktif, mengembalikan NULL atau throw .

Sumber : Kernel Linux, yang tumpukannya tidak melebihi 8 KB!

3
28 дек. jawabannya diberikan unixman83 28 Desember. 2011-12-28 02:16 '12 pada 2:16 2011-12-28 02:16

Untuk kelengkapan, Anda dapat membaca artikel Miro Samek tentang cara menggunakan tumpukan dalam konteks perangkat lunak tertanam .

Banyak masalah

2
25 янв. Balas diberikan oleh Daniel Daranas 25 Jan 2010-01-25 12:22 '10 pada 12:22 2010-01-25 12:22

Pilihan apakah akan mengalokasikan tumpukan atau tumpukan adalah pilihan yang dibuat untuk Anda, tergantung pada bagaimana variabel Anda didistribusikan. Jika Anda mengalokasikan sesuatu secara dinamis, menggunakan panggilan "baru", Anda memilih dari tumpukan. Jika Anda memilih sesuatu sebagai variabel global atau sebagai parameter dalam suatu fungsi, itu dialokasikan dalam tumpukan.

1
01 марта '09 в 8:48 2009-03-01 08:48 jawabannya diberikan oleh Rob Lachlan pada 01 Maret 2009 di 08:48 2009-03-01 08:48

Ini mungkin dijawab dengan cukup baik. Saya ingin mengarahkan Anda ke seri artikel selanjutnya untuk mendapatkan pemahaman yang lebih dalam tentang detail level rendah. Alex Darby memiliki serangkaian artikel untuk memandu Anda dengan debugger. Ini adalah bagian 3 tentang stack. http://www.altdevblogaday.com/2011/12/14/cc-low-level-curriculum-part-3-the-stack/

0
21 июля '12 в 13:41 2012-07-21 13:41 jawabannya diberikan oleh hAcKnRoCk 21 Juli '12 pada 1:41 pm 2012-07-21 13:41

Menurut saya, ada dua faktor penentu.

 1) Scope of variable 2) Performance. 

Saya lebih suka menggunakan stack dalam banyak kasus, tetapi jika Anda membutuhkan akses ke variabel penampilan, Anda dapat menggunakan banyak.

Untuk meningkatkan kinerja saat menggunakan heap, Anda juga dapat menggunakan fungsionalitas untuk membuat blok heap, yang dapat membantu Anda mendapatkan kinerja, daripada mengalokasikan setiap variabel di lokasi memori yang berbeda.

0
01 марта '09 в 12:15 2009-03-01 12:15 jawabannya diberikan dan 01 Maret 09 di 12:15 2009-03-01 12:15