Dalam kasus apa saya menggunakan malloc dan / atau baru?

479

Saya melihat di C ++ ada beberapa cara untuk mengalokasikan dan membebaskan data dan saya mengerti bahwa ketika Anda menelepon mallocAnda harus menelepon freedan ketika Anda menggunakan newoperator Anda harus memasangkan dengan deletedan itu adalah kesalahan untuk mencampur keduanya (misalnya Memanggil free()sesuatu yang telah dibuat dengan newoperator), tapi saya tidak jelas kapan saya harus menggunakan malloc/ freedan kapan saya harus menggunakan new/ deletedalam program dunia nyata saya.

Jika Anda seorang pakar C ++, beri tahu saya aturan apa pun yang Anda ikuti dalam hal ini.

JVApen
sumber
33
Saya hanya ingin menambahkan pengingat bahwa Anda tidak dapat mencampur dua gaya - yaitu, Anda tidak dapat menggunakan yang baru untuk membuat objek dan kemudian memanggil bebas () di atasnya, atau mencoba menghapus blok yang dialokasikan oleh malloc (). Mungkin jelas untuk mengatakannya, tapi tetap saja ...
nsayer
32
Jawaban yang bagus, yang harus saya tambahkan (yang belum saya lihat) adalah bahwa baru / hapus memanggil konstruktor / destruktor untuk Anda, malloc / gratis tidak. Hanya perbedaan yang layak disebutkan.
Bill K
Dengan C ++ modern, saya masih mencoba mencari alasan untuk menggunakan keduanya.
Rahly
Atau jangan gunakan keduanya dan gunakan std: shared_ptr <T>. Maka Anda tidak perlu menghapus sama sekali.
Vincent

Jawaban:

387

Kecuali Anda dipaksa untuk menggunakan C, Anda seharusnya tidak pernah menggunakan malloc . Selalu gunakan new.

Jika Anda membutuhkan banyak data, lakukan saja seperti:

char *pBuffer = new char[1024];

Hati-hati meskipun ini tidak benar:

//This is incorrect - may delete only one element, may corrupt the heap, or worse...
delete pBuffer;

Alih-alih, Anda harus melakukan ini saat menghapus array data:

//This deletes all items in the array
delete[] pBuffer;

Itu new kunci adalah cara C ++ untuk melakukannya, dan itu akan memastikan bahwa tipe Anda akan memanggil konstruktornya . Kata newkunci juga lebih aman-tipe sedangkan malloctidak-aman sama sekali.

Satu-satunya cara saya bisa berpikir itu akan bermanfaat untuk digunakan malloc adalah jika Anda perlu mengubah ukuran buffer data Anda. Kata newkunci tidak memiliki cara analog seperti realloc. The reallocFungsi mungkin bisa memperpanjang ukuran sepotong memori untuk Anda lebih efisien.

Perlu disebutkan bahwa Anda tidak dapat mencampur new/ freedan malloc/ delete.

Catatan: Beberapa jawaban dalam pertanyaan ini tidak valid.

int* p_scalar = new int(5);  // Does not create 5 elements, but initializes to 5
int* p_array  = new int[5];  // Creates 5 elements
Brian R. Bondy
sumber
2
Sehubungan dengan memanggil delete foo ketika Anda harus memanggil delete [] foo, beberapa kompiler akan memperbaikinya secara otomatis untuk Anda dan tidak bocor dan lainnya hanya akan menghapus entri pertama dan bocor. Saya punya beberapa di antaranya dalam beberapa kode dan valgrind akan menemukannya untuk Anda.
KPexEA
30
Jika Anda tidak menggunakan penghapusan yang benar hasilnya tidak terdefinisi . Itu salah. Kenyataan bahwa itu mungkin mendapatkan bagian dari hal yang benar atau bekerja kadang-kadang hanya keberuntungan belaka.
Michael Burr
8
@KPexEA: Sekalipun beberapa penyusun mungkin memperbaiki kesalahan Anda, tetap salah untuk membuatnya terlebih dahulu :) Selalu gunakan delete [] jika perlu.
korona
62
"Kecuali kamu dipaksa untuk menggunakan C, kamu tidak boleh menggunakan malloc. Selalu gunakan yang baru." Mengapa? Apa kemenangan di sini? Untuk objek yang membutuhkan konstruksi, tetapi untuk blok memori, Anda dengan jelas mendokumentasikan dua cara untuk membuat kesalahan pengkodean (semakin mudah ditangkap () vs [] pada array baru dan yang kurang mudah ditangkap vs scaler baru dan hapus scaler). Apa motivasi untuk menggunakan baru / menghapus blok memori mentah?
Ben Supnik
3
@DeadMG: Jika seseorang membuat array untuk digunakan oleh fungsi API asinkron, tidak new[]akan jauh lebih aman daripada std::vector? Jika seseorang menggunakan new[], satu-satunya cara penunjuk akan menjadi tidak valid adalah melalui eksplisit delete, sedangkan memori yang dialokasikan untuk suatu std::vectordapat batal ketika vektor diubah ukurannya atau meninggalkan ruang lingkup. (Perhatikan bahwa ketika menggunakan new[]salah satu harus memungkinkan untuk kemungkinan bahwa seseorang mungkin tidak dapat memanggil deletejika metode async masih tertunda; jika mungkin perlu untuk meninggalkan operasi async, orang mungkin harus mengatur untuk menghapus melalui callback) .
supercat
144

Jawaban singkatnya adalah: jangan gunakan mallocuntuk C ++ tanpa alasan yang bagus untuk melakukannya. mallocmemiliki sejumlah kekurangan saat digunakan dengan C ++, yangnew didefinisikan untuk diatasi.

Kekurangan diperbaiki oleh baru untuk kode C ++

  1. mallocbukan typesafe dengan cara apa pun yang berarti. Di C ++ Anda diminta untuk mengembalikan dari void*. Ini berpotensi menimbulkan banyak masalah:

    #include <stdlib.h>
    
    struct foo {
      double d[5];
    }; 
    
    int main() {
      foo *f1 = malloc(1); // error, no cast
      foo *f2 = static_cast<foo*>(malloc(sizeof(foo)));
      foo *f3 = static_cast<foo*>(malloc(1)); // No error, bad
    }
  2. Ini lebih buruk dari itu. Jika jenis yang dimaksud adalah POD (data lama biasa) maka Anda dapat menggunakan secara semi-bijaksana mallocuntuk mengalokasikan memori untuknya, sepertif2 halnya dalam contoh pertama.

    Namun tidak begitu jelas apakah suatu tipe POD. Fakta bahwa dimungkinkan untuk tipe tertentu untuk berubah dari POD ke non-POD tanpa menghasilkan kesalahan kompiler dan berpotensi sangat sulit untuk men-debug masalah adalah faktor yang signifikan. Sebagai contoh jika seseorang (mungkin programmer lain, selama pemeliharaan, jauh kemudian adalah untuk membuat perubahan yang menyebabkan footidak lagi menjadi POD maka tidak ada kesalahan yang jelas akan muncul pada waktu kompilasi seperti yang Anda harapkan, misalnya:

    struct foo {
      double d[5];
      virtual ~foo() { }
    };

    akan membuat mallocdari f2juga menjadi buruk, tanpa diagnosa yang jelas. Contoh di sini sepele, tetapi mungkin untuk secara tidak sengaja memperkenalkan non-PODness lebih jauh (misalnya dalam kelas dasar, dengan menambahkan anggota non-POD). Jika Anda memiliki C ++ 11 / boost, Anda dapat menggunakanis_pod untuk memeriksa bahwa asumsi ini benar dan menghasilkan kesalahan jika tidak:

    #include <type_traits>
    #include <stdlib.h>
    
    foo *safe_foo_malloc() {
      static_assert(std::is_pod<foo>::value, "foo must be POD");
      return static_cast<foo*>(malloc(sizeof(foo)));
    }

    Meskipun dorongan tidak dapat menentukan apakah suatu tipe POD tanpa C ++ 11 atau ekstensi kompiler lainnya.

  3. mallockembali NULLjika alokasi gagal. newakan melempar std::bad_alloc. Perilaku nanti menggunakan NULLpointer tidak ditentukan. Pengecualian memiliki semantik bersih saat dilempar dan dilempar dari sumber kesalahan. Membungkus mallocdengan tes yang sesuai pada setiap panggilan tampaknya membosankan dan rawan kesalahan. (Anda hanya perlu lupa sekali untuk membatalkan semua pekerjaan bagus itu). Pengecualian dapat diizinkan untuk menyebar ke tingkat di mana penelepon dapat memprosesnya dengan masuk akal, di mana NULLjauh lebih sulit untuk lulus kembali secara bermakna. Kami dapat memperluas safe_foo_mallocfungsi kami untuk melempar pengecualian atau keluar dari program atau memanggil beberapa penangan:

    #include <type_traits>
    #include <stdlib.h>
    
    void my_malloc_failed_handler();
    
    foo *safe_foo_malloc() {
      static_assert(std::is_pod<foo>::value, "foo must be POD");
      foo *mem = static_cast<foo*>(malloc(sizeof(foo)));
      if (!mem) {
         my_malloc_failed_handler();
         // or throw ...
      }
      return mem;
    }
  4. Pada dasarnya mallocadalah fitur C dan newmerupakan fitur C ++. Akibatnya malloctidak bermain bagus dengan konstruktor, itu hanya terlihat mengalokasikan sejumlah byte. Kami dapat memperluas safe_foo_malloclebih lanjut untuk menggunakan penempatan new:

    #include <stdlib.h>
    #include <new>
    
    void my_malloc_failed_handler();
    
    foo *safe_foo_malloc() {
      void *mem = malloc(sizeof(foo));
      if (!mem) {
         my_malloc_failed_handler();
         // or throw ...
      }
      return new (mem)foo();
    }
  5. safe_foo_mallocFungsi kami tidak terlalu umum - idealnya kami menginginkan sesuatu yang dapat menangani semua jenis, bukan hanya foo. Kita dapat mencapai ini dengan templat dan templat variadic untuk konstruktor non-default:

    #include <functional>
    #include <new>
    #include <stdlib.h>
    
    void my_malloc_failed_handler();
    
    template <typename T>
    struct alloc {
      template <typename ...Args>
      static T *safe_malloc(Args&&... args) {
        void *mem = malloc(sizeof(T));
        if (!mem) {
           my_malloc_failed_handler();
           // or throw ...
        }
        return new (mem)T(std::forward(args)...);
      }
    };

    Namun sekarang dalam memperbaiki semua masalah yang kami identifikasi sejauh ini, kami praktis telah menemukan kembali newoperator default . Jika Anda akan menggunakan mallocdan penempatan newmaka Anda mungkin juga hanya newperlu mulai dengan!

Flexo
sumber
27
Terlalu buruk C ++ dibuat structdan classpada dasarnya berarti hal yang sama; Saya ingin tahu apakah akan ada masalah dengan structdicadangkan untuk POD dan mungkin semua classjenis dianggap non-POD. Setiap tipe yang didefinisikan oleh kode yang mendahului penemuan C ++ akan menjadi POD, jadi saya tidak akan berpikir kompatibilitas ke belakang akan menjadi masalah di sana. Apakah ada keuntungan memiliki jenis non-POD yang dinyatakan sebagai structbukan class?
supercat
1
@supercat Agak terlambat tetapi ternyata, membuat structdan classmelakukan hal yang hampir sama adalah keputusan desain yang luar biasa yang sekarang memungkinkan fitur rapi yang disebut "metaclasses" (dari Herb) .
Rakete1111
@ Rakete1111: Pada pandangan pertama, proposal itu terlihat seperti memproses versi bahasa yang menggunakan kata kunci yang diawali dengan dolar seperti $class. Saya tidak yakin apa yang harus dilakukan dengan classdan structmenjadi sinonim.
supercat
@supercat Sistem tipe akan lebih bercabang dua. Dengan memiliki classdan structmengartikan hal yang sama secara efektif, Anda dapat melakukan transformasi sewenang-wenang terhadap mereka ( $class) tanpa khawatir membuat classa structdan sebaliknya.
Rakete1111
@ Rakete1111: Jika beberapa jenis operasi dan transformasi aman dengan beberapa tipe tetapi tidak yang lain, memiliki tipe yang secara langsung mengidentifikasi hal itu, dan memiliki kompiler menolak operasi dan transformasi yang tidak aman, akan tampak lebih baik daripada memiliki perubahan pada metaclass yang digunakan dalam cara yang hanya cocok untuk PODS, dapatkan diam-diam diubah menjadi non-PODS.
supercat
53

Dari C ++ FQA Lite :

[16.4] Mengapa saya harus menggunakan malloc () lama yang baru dan bukan yang dapat dipercaya?

FAQ: baru / hapus panggilan konstruktor / destruktor; baru adalah tipe aman, malloc tidak; baru dapat diganti oleh suatu kelas.

FQA: Keutamaan baru yang disebutkan oleh FAQ bukanlah kebajikan, karena konstruktor, destruktor, dan kelebihan beban operator adalah sampah (lihat apa yang terjadi ketika Anda tidak memiliki pengumpulan sampah?), Dan masalah keamanan jenis sangat kecil di sini (biasanya Anda memiliki untuk membuang void * dikembalikan oleh malloc ke tipe pointer kanan untuk menetapkannya ke variabel pointer yang diketik, yang mungkin mengganggu, tetapi jauh dari "tidak aman").

Oh, dan menggunakan malloc lama yang dapat dipercaya memungkinkan untuk menggunakan realall yang sama-sama dapat dipercaya & lama. Sayang sekali kami tidak memiliki perpanjangan operator baru yang mengkilap atau sesuatu.

Namun, yang baru tidak cukup buruk untuk membenarkan penyimpangan dari gaya umum yang digunakan di seluruh bahasa, bahkan ketika bahasa C ++. Secara khusus, kelas dengan konstruktor non-sepele akan bertingkah fatal dengan cara jika Anda hanya malloc objek. Jadi mengapa tidak menggunakan yang baru di seluruh kode? Orang-orang jarang membebani operator baru, jadi mungkin tidak akan menghalangi Anda terlalu banyak. Dan jika mereka melakukan overload baru, Anda selalu dapat meminta mereka untuk berhenti.

Maaf, saya tidak bisa menolak. :)

Matthias Benkard
sumber
7
Itu adalah kerusuhan ! Terima kasih.
dmckee --- ex-moderator kitten
8
Saya tidak dapat menganggap komentar ini serius karena jelas memproyeksikan bias penulis terhadap C ++. C ++ adalah bahasa yang digunakan untuk membuat perangkat lunak yang berorientasi pada kinerja, dan seorang pengumpul sampah hanya dapat merusak tujuannya. Saya tidak setuju dengan seluruh jawaban Anda!
Miguel
1
@Miguel Anda melewatkan lelucon itu.
Dan Bechard
50

Selalu gunakan yang baru di C ++. Jika Anda membutuhkan blok memori yang tidak diketik, Anda dapat menggunakan operator baru secara langsung:

void *p = operator new(size);
   ...
operator delete(p);
Ferruccio
sumber
3
menarik, saya selalu hanya mengalokasikan array unsigned char ketika saya membutuhkan buffer data mentah seperti ini.
Greg Rogers
Hati-hati semantiknya harus seperti ini: p_var = tipe baru (initializer); Bukan ukuran.
Brian R. Bondy
11
Tidak jika Anda memanggil operator baru secara langsung, maka dibutuhkan jumlah byte untuk dialokasikan sebagai parameter.
Ferruccio
1
Hrm tidak yakin, saya belum pernah mendengar sintaks ini.
Brian R. Bondy
9
Kebalikan dari operator newadalah operator delete. Ini bukan tindakan yang didefinisikan dengan baik untuk memanggil deleteekspresi dengan tipe void*.
CB Bailey
33

Gunakan mallocdan hanya untuk mengalokasikan memori yang akan dikelola oleh perpustakaan c-centric dan API. Gunakan dan (dan variannya) untuk semua yang Anda kontrol.free newdelete[]

dmckee --- mantan kucing moderator
sumber
10
Juga perhatikan bahwa pustaka C yang ditulis dengan baik akan menyembunyikan malloc dan gratis secara internal, ini adalah bagaimana programmer C harus bekerja.
Dacav
@ dmckee apakah Anda memiliki contoh C ++ menggunakan pustaka c-centric oleh malloc dan gratis?
milesma
1
@Dacav: Jika fungsi C akan menerima pointer ke objek yang harus tetap digunakan setelah fungsi kembali, dan penelepon tidak memiliki cara untuk mengetahui kapan objek masih dibutuhkan, itu akan sangat masuk akal untuk fungsi tersebut untuk menentukan bahwa pointer harus dibuat dengan malloc. Demikian juga jika fungsi seperti strdupperlu membuat objek dan mengembalikannya ke pemanggil, sangat masuk akal untuk menentukan bahwa pemanggil harus memanggil freeobjek ketika tidak lagi diperlukan. Bagaimana bisa fungsi-fungsi tersebut menghindari mengekspos penggunaan malloc / gratis untuk pemanggil?
supercat
@supercat, ada sesuatu yang secara inheren salah dalam memiliki fungsi C menerima pointer ke objek, karena C tidak mengetahui objek sama sekali. Secara umum saya percaya pendekatan terbaik adalah memiliki pembungkus semantik di sekitar alokasi / deallokasi juga di C. Itu masih bisa diterima, tetapi kurang fleksibel, jika perpustakaan C meminta penelepon untuk pra-mengalokasikan dan / atau membatalkan alokasi memori. Jika fungsi C melakukan ini dan mengklaim kepemilikan pada memori yang dialokasikan, Anda secara implisit diharuskan untuk mengalokasikannya dengan malloc.
Dacav
@supercat Salah satu contoh paket setiap hari yang saya yakin semua orang telah gunakan adalah libgmp. Jika Anda pernah menggunakan enkripsi atau perangkat lunak open-source berdasarkan enkripsi semacam itu (yang sangat mungkin) maka Anda mungkin menggunakan perpustakaan aritmatika presisi sewenang-wenang yang perlu menumbuhkan dan mengecilkan data internalnya sendiri. Ini dilakukan menggunakan fungsi inisialisasi ... dan kemudian Anda harus bertanya-tanya, bagaimana Anda menggunakan kode C yang merupakan libgmp, di C ++, tanpa mengkompilasi ulang di C ++? Sekarang dengan itu (penghubung) dalam pikiran, pikirkan tentang itu ... mengapa ada orang yang masuk akal yang pernah dimasukkan ke mallocdalam C ++?
autis
31

baru vs malloc ()

1) newadalah operator yang , sementara malloc()adalah fungsi .

2) newmemanggil konstruktor , sementaramalloc() tidak.

3) newmengembalikan tipe data yang tepat , sementara malloc()mengembalikan batal * .

4) newtidak pernah mengembalikan NULL (akan gagal) sementaramalloc() mengembalikan NULL

5) Realokasi memori tidak ditangani oleh new selagi malloc()bisa

Yogeesh HT
sumber
6
Hai, Untuk poin 4), baru dapat diinstruksikan untuk mengembalikan NULL pada kegagalan. char* ptr = new (std::nothrow) char [323232];
Singh
1
6) menciptakan baru dari argumen konstruktor, sedangkan malloc menggunakan ukuran.
Evan Moran
ada juga newfungsi
Ma Ming
Jika Anda begitu cenderung di C untuk mengalokasikan , saya berharap bahwa Anda akan menggunakan reallocdaripada malloc, dan mulai dengan variabel pointer Anda dijalankan untuk NULL. Jika Anda ingin sepotong memori resizable di C ++, di sisi lain, saya akan menyarankan std::vectorsebagai kebalikan dari realloc... Itu atau file.
autis
19

Untuk menjawab pertanyaan Anda, Anda harus tahu perbedaan antara mallocdannew . Perbedaannya sederhana:

malloc mengalokasikan memori , sementara new mengalokasikan memori DAN memanggil konstruktor dari objek Anda mengalokasikan memori untuk.

Jadi, kecuali Anda dibatasi untuk C, Anda tidak boleh menggunakan malloc, terutama ketika berhadapan dengan objek C ++. Itu akan menjadi resep untuk merusak program Anda.

Juga perbedaan antara freedan deletecukup sama. Perbedaannya adalah bahwa deleteakan memanggil destruktor objek Anda selain membebaskan memori.

Fisikawan Kuantum
sumber
13

Ada satu perbedaan besar antara mallocdan new.mallocmengalokasikan memori. Ini bagus untuk C, karena di C, benjolan memori adalah objek.

Di C ++, jika Anda tidak berurusan dengan tipe POD (yang mirip dengan tipe C) Anda harus memanggil konstruktor pada lokasi memori untuk benar-benar memiliki objek di sana. Jenis non-POD sangat umum di C ++, karena banyak fitur C ++ membuat objek secara otomatis non-POD.

newmengalokasikan memori dan membuat objek di lokasi memori itu. Untuk jenis non-POD ini berarti memanggil konstruktor.

Jika Anda melakukan sesuatu seperti ini:

non_pod_type* p = (non_pod_type*) malloc(sizeof *p);

Pointer yang Anda peroleh tidak dapat direferensikan karena tidak menunjuk ke objek. Anda harus memanggil konstruktor sebelum dapat menggunakannya (dan ini dilakukan dengan menggunakan penempatannew ).

Sebaliknya, jika Anda melakukannya:

non_pod_type* p = new non_pod_type();

Anda mendapatkan pointer yang selalu valid, karena new membuat objek.

Bahkan untuk tipe POD, ada perbedaan yang signifikan antara keduanya:

pod_type* p = (pod_type*) malloc(sizeof *p);
std::cout << p->foo;

Sepotong kode ini akan mencetak nilai yang tidak ditentukan, karena objek POD yang dibuat oleh malloctidak diinisialisasi.

Dengan new, Anda bisa menentukan konstruktor yang akan dipanggil, dan dengan demikian mendapatkan nilai yang terdefinisi dengan baik.

pod_type* p = new pod_type();
std::cout << p->foo; // prints 0

Jika Anda benar-benar menginginkannya, Anda dapat menggunakan gunakan newuntuk mendapatkan objek POD yang tidak diinisialisasi. Lihat jawaban lain ini untuk informasi lebih lanjut tentang itu.

Perbedaan lainnya adalah perilaku pada kegagalan. Ketika gagal mengalokasikan memori, mallocmengembalikan pointer nol, sementaranew melempar pengecualian.

Yang pertama mengharuskan Anda untuk menguji setiap pointer yang dikembalikan sebelum menggunakannya, sementara yang berikutnya akan selalu menghasilkan pointer yang valid.

Untuk alasan ini, dalam kode C ++ Anda harus menggunakan new, dan tidak malloc. Tetapi meskipun demikian, Anda tidak boleh menggunakan new"di tempat terbuka", karena ia memperoleh sumber daya yang perlu Anda rilis nanti. Ketika Anda menggunakan, newAnda harus segera menyerahkan hasilnya ke kelas pengelola sumber daya:

std::unique_ptr<T> p = std::unique_ptr<T>(new T()); // this won't leak
R. Martinho Fernandes
sumber
7

Alokasi dinamis hanya diperlukan ketika masa hidup objek harus berbeda dari ruang lingkup yang dibuatnya (Ini berlaku juga untuk membuat ruang lingkup lebih kecil sebagai lebih besar) dan Anda memiliki alasan khusus di mana menyimpannya dengan nilai tidak kerja.

Sebagai contoh:

 std::vector<int> *createVector(); // Bad
 std::vector<int> createVector();  // Good

 auto v = new std::vector<int>(); // Bad
 auto result = calculate(/*optional output = */ v);
 auto v = std::vector<int>(); // Good
 auto result = calculate(/*optional output = */ &v);

Dari C ++ 11 dan seterusnya, kita harus std::unique_ptrberurusan dengan memori yang dialokasikan, yang berisi kepemilikan memori yang dialokasikan.std::shared_ptrdibuat ketika Anda harus berbagi kepemilikan. (Anda akan membutuhkan ini kurang dari yang Anda harapkan dalam program yang bagus)

Membuat instance menjadi sangat mudah:

auto instance = std::make_unique<Class>(/*args*/); // C++14
auto instance = std::make_unique<Class>(new Class(/*args*/)); // C++11
auto instance = std::make_unique<Class[]>(42); // C++14
auto instance = std::make_unique<Class[]>(new Class[](42)); // C++11

C ++ 17 juga menambahkan std::optionalyang dapat mencegah Anda dari membutuhkan alokasi memori

auto optInstance = std::optional<Class>{};
if (condition)
    optInstance = Class{};

Segera setelah 'instans' keluar dari ruang lingkup, memori dibersihkan. Mentransfer kepemilikan juga mudah:

 auto vector = std::vector<std::unique_ptr<Interface>>{};
 auto instance = std::make_unique<Class>();
 vector.push_back(std::move(instance)); // std::move -> transfer (most of the time)

Jadi kapan Anda masih membutuhkannya new? Hampir tidak pernah dari C ++ 11 on. Sebagian besar yang Anda gunakan std::make_uniquesampai Anda mencapai titik di mana Anda menekan API yang mentransfer kepemilikan melalui pointer mentah.

 auto instance = std::make_unique<Class>();
 legacyFunction(instance.release()); // Ownership being transferred

 auto instance = std::unique_ptr<Class>{legacyFunction()}; // Ownership being captured in unique_ptr

Dalam C ++ 98/03, Anda harus melakukan manajemen memori manual. Jika Anda berada dalam kasus ini, cobalah memutakhirkan ke versi standar yang lebih baru. Jika Anda macet:

 auto instance = new Class(); // Allocate memory
 delete instance;             // Deallocate
 auto instances = new Class[42](); // Allocate memory
 delete[] instances;               // Deallocate

Pastikan Anda melacak kepemilikan dengan benar agar tidak ada kebocoran memori! Pindah semantik juga belum berfungsi.

Jadi, kapan kita perlu malloc di C ++? Satu-satunya alasan yang valid adalah untuk mengalokasikan memori dan menginisialisasi nanti melalui penempatan baru.

 auto instanceBlob = std::malloc(sizeof(Class)); // Allocate memory
 auto instance = new(instanceBlob)Class{}; // Initialize via constructor
 instance.~Class(); // Destroy via destructor
 std::free(instanceBlob); // Deallocate the memory

Meskipun, di atas valid, ini dapat dilakukan melalui operator baru juga. std::vectoradalah contoh yang bagus untuk ini.

Akhirnya, kita masih memiliki gajah di dalam ruangan: C. Jika Anda harus bekerja dengan C-library di mana memori dialokasikan dalam kode C ++ dan dibebaskan dalam kode C (atau sebaliknya), Anda dipaksa untuk menggunakan malloc / gratis.

Jika Anda berada dalam kasus ini, lupakan fungsi virtual, fungsi anggota, kelas ... Hanya struct dengan POD di dalamnya yang diizinkan.

Beberapa pengecualian terhadap aturan:

  • Anda sedang menulis perpustakaan standar dengan struktur data lanjutan di mana malloc sesuai
  • Anda harus mengalokasikan sejumlah besar memori (Dalam salinan memori file 10GB?)
  • Anda memiliki perkakas yang mencegah Anda menggunakan konstruksi tertentu
  • Anda perlu menyimpan jenis yang tidak lengkap
JVApen
sumber
6

Ada beberapa hal yang newtidak yang malloctidak:

  1. new membangun objek dengan memanggil konstruktor objek itu
  2. new tidak memerlukan typecasting memori yang dialokasikan.
  3. Itu tidak memerlukan sejumlah memori untuk dialokasikan, melainkan membutuhkan sejumlah objek yang akan dibangun.

Jadi, jika Anda menggunakan malloc, maka Anda perlu melakukan hal-hal di atas secara eksplisit, yang tidak selalu praktis. Selain itu, newbisa kelebihan beban tetapi malloctidak bisa.

herohuyongtao
sumber
5

Jika Anda bekerja dengan data yang tidak memerlukan konstruksi / penghancuran dan membutuhkan realokasi (mis., Array int yang besar), maka saya percaya malloc / free adalah pilihan yang baik karena memberi Anda realall, yang jauh lebih cepat daripada memcpy baru -delete (ada di kotak Linux saya, tapi saya kira ini mungkin tergantung platform). Jika Anda bekerja dengan objek C ++ yang bukan POD dan membutuhkan konstruksi / penghancuran, maka Anda harus menggunakan operator baru dan menghapus.

Lagi pula, saya tidak mengerti mengapa Anda tidak harus menggunakan keduanya (asalkan Anda membebaskan memori malloced Anda dan menghapus objek yang dialokasikan dengan yang baru) jika dapat mengambil keuntungan dari peningkatan kecepatan (kadang-kadang yang signifikan, jika Anda realokasi array besar POD) yang realall dapat berikan kepada Anda.

Kecuali Anda membutuhkannya, Anda harus tetap menggunakan / menghapus yang baru di C ++.

PSkocik
sumber
3

Jika Anda memiliki kode C yang ingin Anda portingkan ke C ++, Anda dapat meninggalkan panggilan malloc () di dalamnya. Untuk kode C ++ baru, saya sarankan menggunakan yang baru.

Fred Larson
sumber
3

Jika Anda menggunakan C ++, coba gunakan baru / hapus alih-alih malloc / calloc karena mereka adalah operator. Untuk malloc / calloc, Anda perlu memasukkan header lain. Jangan mencampur dua bahasa berbeda dalam kode yang sama. Pekerjaan mereka serupa dalam segala hal, keduanya mengalokasikan memori secara dinamis dari segmen heap di tabel hash.

pengguna3488100
sumber
2

new akan menginisialisasi nilai default struct dan dengan benar menghubungkan referensi ke dalamnya.

Misalnya

struct test_s {
    int some_strange_name = 1;
    int &easy = some_strange_name;
}

Jadi new struct test_sakan mengembalikan struktur yang diinisialisasi dengan referensi yang berfungsi, sedangkan versi malloc'ed tidak memiliki nilai default dan referensi intern tidak diinisialisasi.

lama12345
sumber
1

Dari perspektif yang lebih rendah, baru akan menginisialisasi semua memori sebelum memberikan memori sedangkan malloc akan menyimpan konten asli memori.

Peiti Li
sumber
4
baru tidak secara umum menginisialisasi memori, meskipun ada cara untuk mewujudkannya: lihat stackoverflow.com/questions/2204176/… untuk satu diskusi tentangnya.
wjl
0

Dalam skenario berikut, kami tidak dapat menggunakan yang baru karena memanggil konstruktor.

class  B  {
private:
    B *ptr;
    int x;
public:
    B(int n)  {
        cout<<"B: ctr"<<endl;
        //ptr = new B;  //keep calling ctr, result is segmentation fault
        ptr = (B *)malloc(sizeof(B));
        x = n;
        ptr->x = n + 10;
    }
    ~B()  {
        //delete ptr;
        free(ptr);
        cout<<"B: dtr"<<endl;
    }
};
Barry
sumber
0

The newdan deleteoperator dapat beroperasi pada kelas dan struktur, sedangkan mallocdan freehanya bekerja dengan blok memori yang perlu menjadi pemain.

Menggunakan new/deleteakan membantu meningkatkan kode Anda karena Anda tidak perlu membuang memori yang dialokasikan ke struktur data yang diperlukan.

selwyn
sumber
0

Rare case untuk dipertimbangkan menggunakan malloc / free daripada new / delete adalah ketika Anda mengalokasikan dan kemudian realokasi (tipe pod sederhana, bukan objek) menggunakan realloc karena tidak ada fungsi yang mirip dengan realall di C ++ (meskipun ini dapat dilakukan dengan menggunakan lebih banyak pendekatan C ++).

Florentino Tuason
sumber
-4

malloc () digunakan untuk secara dinamis menetapkan memori dalam C sementara pekerjaan yang sama dilakukan oleh new () dalam c ++. Jadi, Anda tidak dapat mencampur konvensi pengkodean 2 bahasa. Akan lebih baik jika Anda meminta perbedaan antara calloc dan malloc ()

Hitesh Ahuja
sumber
2
Anda dapat (tetapi hampir selalu tidak seharusnya) menggunakan mallocC ++.
interjay
1
Anda juga melewatkan poin utama yang harus Anda hindari untuk alokasi memori dinamis, kecuali melakukannya melalui smart pointer. Anda hanya mengatur diri Anda untuk kesakitan orang bijak lain
thecoshman