Hangi durumlarda malloc ve / veya new kullanırım?


479

C ++ 'da veri tahsis etmenin ve serbest bırakmanın birden fazla yolu olduğunu görüyorum ve aradığınızda aramanız mallocgerektiğini freeve newoperatörü kullandığınızda eşleştirmeniz gerektiğini deleteve ikisini karıştırmanın bir hata olduğunu anlıyorum (örneğin free(), oluşturulan bir şeye çağrı yapmak) ile new) operatörü, ama ben kullanmalıyım zaman net değilim malloc/ freeve kullanmam gereken zaman new/ deletebenim gerçek dünya programlarında.

Bir C ++ uzmanıysanız, lütfen bu konuda izlediğiniz herhangi bir genel kural veya konvansiyonu bana bildirin.


33
Sadece iki stili karıştıramayacağınıza dair bir hatırlatma eklemek istiyorum - yani, bir nesne oluşturmak için new kullanamazsınız ve sonra free () öğesini çağırmazsınız veya malloc () tarafından ayrılmış bir bloğu silmeye çalışamazsınız. Muhtemelen söylemek için açık, ama yine de ...
nsayer

32
İyi cevaplar, eklemek zorunda olduğum tek şey (görmedim) yeni / delete yapıcı / yıkıcı sizin için çağırır, malloc / free değil. Bahsetmeye değer bir fark.
Bill K

Modern C ++ ile, hala kullanmak için bir neden bulmaya çalışıyorum.
Rahly

Veya ikisini de kullanmayın ve std: shared_ptr <T> ile devam edin. O zaman hiç silmek zorunda kalmazsınız.
Vincent

Yanıtlar:


387

C kullanmaya zorlanmadıkça, asla kullanmamalısınız malloc . Her zaman kullanın new.

Büyük miktarda veriye ihtiyacınız varsa, aşağıdakine benzer bir şey yapın:

char *pBuffer = new char[1024];

Bu doğru olmasa da dikkatli olun:

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

Bunun yerine, bir veri dizisini silerken bunu yapmalısınız:

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

newAnahtar kelime bunu yapmanın C ++ yoludur ve bu senin türünün gelmiş sağlayacaktır yapıcı denir . newAnahtar kelime de daha fazladır tip-güvenli oysa malloctip-güvenli değildir hiç.

Kullanmanın faydalı olacağını düşünebilmemin tek yolu , veri tamponunuzun boyutunu değiştirmenizmalloc gerektiğinde olurdu . Anahtar kelime gibi benzer bir şekilde yok . Fonksiyon daha verimli sizin için belleğin bir yığın boyutunu genişletmek mümkün olabilir.newreallocrealloc

new/ freeVe malloc/ öğelerini karıştıramayacağınızı belirtmek gerekir delete.

Not: Bu sorudaki bazı cevaplar geçersiz.

int* p_scalar = new int(5);  // Does not create 5 elements, but initializes to 5
int* p_array  = new int[5];  // Creates 5 elements

2
Delete [] foo'yu çağırmanız gerektiğinde delete foo'yu çağırmayla ilgili olarak, bazı derleyiciler bunu sizin için otomatik olarak düzeltir ve sızıntıyı değil, diğerleri yalnızca ilk girişi ve sızıntıyı siler. Bazı kod bunlardan birkaç vardı ve valgrind bunları sizin için bulacaksınız.
KPexEA

30
Doğru silme yöntemini kullanmazsanız sonuç tanımsız olur . Yanlış. İşin bir kısmını doğru bir şekilde yapabileceği veya bazen çalışabileceği gerçeği sadece kör şanstır.
Michael Burr

8
@KPexEA: Bazı derleyiciler hatalarınızı düzeltse bile, onları ilk etapta yapmak hala yanlıştır :) Uygun olan yerlerde daima delete [] kullanın.
korona

62
"C kullanmaya mecbur olmadığınız sürece, asla malloc kullanmamalısınız. Daima yeni kullanın." Neden? Buradaki kazanç nedir? Nesneler için yapıya ihtiyacımız var, ancak bellek blokları için, kodlama hataları (yeni olarak daha kolay yakalanır () vs [] ve daha az kolayca yakalanan uyumsuz dizi ve ölçekleyici yeni ve sil) için iki yolu açıkça belgelersiniz. Ham bellek blokları için yeni / sil komutunu kullanma motivasyonu nedir?
Ben Supnik

3
@DeadMG: Biri zaman uyumsuz bir API işlevi tarafından kullanılmak üzere bir dizi oluşturuyorsa, bundan new[]daha güvenli olmaz std::vectormı? Eğer biri kullanılırsa new[], imlecin geçersiz hale gelmesinin tek yolu açık olabilir delete, oysa bir std::vectorvektör için yeniden boyutlandırıldığında veya kapsamdan çıktığında bir için ayrılan bellek geçersiz kılınabilir. ( new[]Birini kullanırken, zaman deleteuyumsuz yöntem hala beklemedeyse arama yapamayabilir ; zaman uyumsuz bir işlemden vazgeçmek gerekirse, geri arama yoluyla silme ayarlaması gerekebilir) .
supercat

144

Kısa cevap: mallocC ++ için gerçekten iyi bir neden olmadan kullanmayın . üstesinden gelmek için tanımlanan mallocC ++ ile kullanıldığında bir takım eksikliklere sahiptir new.

C ++ kodu için yeni ile giderilen hatalar

  1. mallochiçbir şekilde anlamlı değildir. C ++ 'da dönüşü almanız gerekir void*. Bu potansiyel olarak birçok sorun yaratır:

    #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. Yine de bundan daha kötü. Söz konusu tür POD (düz eski veriler) ise, ilk örnekte mallocolduğu gibi bellek ayırmak için yarı duyarlı bir şekilde kullanabilirsiniz f2.

    Bir tür POD ise çok açık değildir. Belirli bir türün POD'dan POD'a dönüşmemesi, sonuçta derleyici hatası olmadan ve potansiyel olarak hata ayıklamakta zorlanma olasılığı önemli bir faktördür. Örneğin, bir kişi (muhtemelen başka bir programcı, bakım sırasında, çok daha sonra, fooartık POD olmamasına neden olan bir değişiklik yapacaksa , derlediğiniz zaman umduğunuz gibi açık bir hata görünmez, örneğin:

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

    yapacak mallocbir f2herhangi belirgin teşhis olmadan da olur bad. Buradaki örnek önemsizdir, ancak yanlışlıkla PODness'i çok daha uzağa tanıtmak mümkündür (örneğin, bir temel sınıfta, POD üyesi olmayan bir üye ekleyerek). C ++ 11 / boost varsa, is_podbu varsayımın doğru olup olmadığını kontrol etmek ve eğer değilse bir hata üretmek için kullanabilirsiniz:

    #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)));
    }

    Her ne kadar boost, bir türün C ++ 11 veya başka bir derleyici uzantısı olmadan POD olup olmadığını belirleyemese de .

  3. mallocNULLayırma başarısız olursa döndürür . newatacak std::bad_alloc. Daha sonra bir NULLişaretçi kullanma davranışı tanımlanmamıştır. Bir istisna atıldığında temiz semantiğe sahiptir ve hatanın kaynağından atılır. mallocHer aramada uygun bir testle sarmak sıkıcı ve hataya açık görünüyor. (Tüm bu iyi işleri geri almak için sadece bir kez unutmanız gerekir). Bir istisnanın, bir arayanın onu NULLanlamlı bir şekilde işleyebildiği bir seviyeye yayılmasına izin verilebilir; safe_foo_mallocBir istisna atmak veya programdan çıkmak veya bazı işleyicileri çağırmak için işlevimizi uzatabiliriz :

    #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. Temelde mallocbir C özelliğidir ve newbir C ++ özelliğidir. Sonuç mallocolarak inşaatçılar ile iyi oynamaz, sadece bir yığın bayt tahsis etmeye bakar. safe_foo_mallocYerleşimi kullanmak için daha fazlasını genişletebiliriz 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. İşlevimiz safe_foo_mallocçok genel değil - ideal olarak, sadece her tür işi yapabilecek bir şey istemiyoruz foo. Bunu, varsayılan olmayan kurucular için şablonlarla ve değişken şablonlarla başarabiliriz:

    #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)...);
      }
    };

    Şimdi şimdiye kadar tespit ettiğimiz tüm sorunları giderirken, varsayılan newoperatörü pratikte yeniden keşfettik . Kullanacak mallocve yerleştirecekseniz , başlamak için newde kullanabilirsiniz new!


27
Çok kötü C ++ yapılmış structve classtemelde aynı şey demek; structPOD'lara ayrılmış olma ve muhtemelen tüm classtürlerin POD olmayanlar olarak kabul edilmesinde herhangi bir sorun olup olmadığını merak ediyorum . C ++ icatından önce gelen kodla tanımlanan herhangi bir tür mutlaka POD'lar olacaktır, bu yüzden geriye dönük uyumluluğun orada bir sorun olacağını düşünmezdim. POD olmayan türlerin structyerine bildirilmesinin avantajları var classmı?
supercat

1
@supercat Biraz geç ama ortaya çıktıkça, hemen hemen aynı şeyi yapmak structve classyapmak, "metaclasses" (Herb'den) adlı düzgün bir özellik sağlayan harika bir tasarım kararıydı .
Rakete1111

@ Rakete1111: İlk bakışta, bu teklif, dolar ön ekli anahtar kelimeler kullanan dilin bir sürümünü önceden işlemiş gibi görünüyor $class. Ancak bunun ne anlama geldiğinden classve structeş anlamlı olduklarından emin değilim .
supercat

@supercat Tip sistemi daha fazla çatallanabiliyordu. Aynı şeyi etkili bir şekilde elde etmek classve kastederek, a ve tersini yapma endişesi olmadan structüzerlerinde rasgele dönüşümler yapabilirsiniz ( $class) . classstruct
Rakete1111

@ Rakete1111: Bazı tür operasyonlar ve dönüşümler bazı türler için güvenli, ancak diğerleri için güvenli değilse, türün bunu doğrudan tanımlaması ve bir derleyicinin güvenli olmayan işlemleri ve dönüşümleri reddetmesi, yalnızca bir PODS için uygun olan yollar sessizce PODS olmayan bir şekilde değiştirilir.
supercat

53

Gönderen C ++ FQA Lite :

[16.4] Güvenilir eski malloc () yerine neden yeni kullanmalıyım?

SSS: yeni / sil çağrı yapıcı / yıkıcı; yeni tip güvenlidir, malloc değildir; yeni bir sınıf tarafından geçersiz kılınabilir.

FQA: SSS tarafından belirtilen yeni erdemler erdem değildir, çünkü inşaatçılar, yıkıcılar ve operatör aşırı yüklemesi çöptür (çöp toplama olmadığında ne olur?) Ve tür güvenliği sorunu gerçekten çok küçüktür (normalde malloc tarafından döndürülen boşluğu * rahatsız edici olabilecek ancak "güvensiz" olmaktan çok uzak bir işaretçi değişkenine atamak için sağ işaretçi türüne atamak).

Oh, ve güvenilir eski malloc kullanmak eşit derecede güvenilir ve eski realloc kullanmayı mümkün kılar. Çok kötü, yeni bir operatörünüzü yenilememiz falan yok.

Yine de, yeni, dil C ++ olsa bile, bir dil boyunca kullanılan ortak stilden bir sapmayı haklı çıkaracak kadar kötü değildir. Özellikle, önemsiz kurucuları olmayan sınıflar, nesneleri basitçe bozursanız ölümcül şekilde yanlış davranacaktır. Peki neden kod boyunca yeni kullanmıyorsunuz? İnsanlar nadiren operatöre yeni yükler, bu yüzden muhtemelen çok fazla yolunuza çıkmaz. Ve eğer aşırı yüklenirlerse, her zaman durmalarını isteyebilirsiniz.

Üzgünüm, dayanamadım. :)


7
Bu bir isyan ! Teşekkürler.
dmckee --- ex-moderator kitten

8
Bu yorumu ciddiye alamıyorum çünkü yazarın C ++ 'ya karşı önyargılı olduğunu açıkça gösteriyor. C ++, performans odaklı yazılım oluşturmak için kullanılan bir dildir ve bir çöp toplayıcı yalnızca amacına zarar verebilir. Tüm cevabınıza katılmıyorum!
Miguel

1
@Miguel Şakayı kaçırdın.
Dan Bechard

50

C ++ 'da her zaman yeniyi kullanın. Türlenmemiş bir bellek bloğuna ihtiyacınız varsa, yeni operatörü doğrudan kullanabilirsiniz:

void *p = operator new(size);
   ...
operator delete(p);

3
ilginç, ben her zaman sadece böyle bir ham veri tamponu gerektiğinde imzasız char bir dizi tahsis.
Greg Rogers

Semmantiğin şöyle olması gerektiğine dikkat edin: p_var = yeni tip (başlatıcı); Boyut değil.
Brian R. Bondy

11
Operatörü doğrudan yeni çağırırsanız, parametre olarak ayrılacak bayt sayısını alır.
Ferruccio

1
Hrm emin değilim, bu sözdizimini hiç duymadım.
Brian R. Bondy

9
Karşıt operator newIS operator delete. deleteTürü olan bir ifadeyi çağırmak iyi tanımlanmış bir eylem değildir void*.
CB Bailey

33

Kullanım mallocve sadece c-merkezli kütüphaneler ve API tarafından yönetilen olacak bellek ayırma için. Kontrol ettiğiniz her şey için ve (ve varyantlarını) kullanın .free newdelete[]


10
Ayrıca, iyi yazılmış C kütüphanesinin malloc'u gizleyeceğini ve dahili olarak serbest kalacağını, C programcısının bu şekilde çalışması gerektiğini unutmayın.
Dacav

@dmckee malloc ve free tarafından c-merkezli kütüphaneleri kullanan bir C ++ örneğiniz var mı?
milesma

1
@Dacav: Bir C işlevi, işlev döndükten sonra kullanmaya devam etmesi gereken bir nesneye bir işaretçi kabul ederse ve arayanın nesneye ne zaman ihtiyaç duyulduğunu bilmesinin bir yolu olmazsa, işlev için mükemmel bir şekilde makul olacaktır. işaretçinin ile oluşturulması gerektiğini belirtmek için malloc. Benzer şekilde, bir fonksiyonun strdupbir nesne yaratması ve onu bir arayana geri döndürmesi gerekiyorsa, freeartık gerekmediğinde arayanın nesneyi çağırması gerektiğini belirtmek kesinlikle mantıklıdır . Bu işlevler malloc / free kullanımlarını arayan kişiye göstermekten nasıl kaçınabilir?
supercat

@supercat, C işlevinin nesneler için bir işaretçi kabul etmesinin doğasında yanlış olan bir şey vardır, çünkü C hiçbir nesnenin farkında değildir. Genel olarak en iyi yaklaşımın C'de de tahsis / dağıtma etrafında semantik sarmalayıcılara sahip olduğuna inanıyorum. Bir C kütüphanesi arayandan hafızayı önceden ayırmasını ve / veya yeniden yerleştirmesini istiyorsa hala kabul edilebilir, ancak daha az esnek olabilir. Bir C işlevi bunu yapıyorsa ve ayrılan bellekte sahiplik iddiasında bulunuyorsa, bunu dolaylı olarak malloc ile ayırmanız gerekir.
Dacav

@supercat Herkesin kullandığı günlük paketlere bir örnek libgmp. Daha önce bu tür şifrelemeye dayalı herhangi bir açık kaynaklı şifreleme veya yazılım kullandıysanız (ki bu büyük olasılıkla), muhtemelen kendi dahili verilerini büyütmesi ve küçültmesi gereken keyfi bir hassas aritmetik kitaplığı kullandınız. Bu bir başlatma işlevi kullanılarak yapılır ... ve sonra merak etmelisiniz, C ++ 'da yeniden derlemeden C ++' ta libgmp olan C kodunu nasıl kullanıyorsunuz? Şimdi akılda (bağlayıcı) ile, ... niye her mantıklı insan olur bunu düşünmek hiç koymak mallocC ++?
otistik

31

yeni vs malloc ()

1) newbir operatör iken malloc()bir işlevdir .

2) yapıcılarınew çağırır , ancak yapmaz.malloc()

3) newdöndüren kesin veri türü ise, malloc()döner void * .

4) newasla NULL döndürmez (başarısızlığa neden olur) malloc()NULL döndürür

5) bellek Yeniden Tahsisi tarafından işlenen newise malloc()kutu


6
Merhaba, 4. nokta için), yeni hata durumunda NULL döndürmesi söylenebilir. char* ptr = new (std::nothrow) char [323232];
Singh

1
6) malloc boyutu kullanırken, yapıcı argümanlarından yeni oluşturur.
Evan Moran

bir newişlevi de var
Ma Ming

Eğer C'yi yeniden tahsis edecek kadar eğimli olsaydınız, bunun reallocyerine kullanmak isteyeceğinizi mallocve işaretçi değişkeniniz başlatıldığında başlayacağınızı umuyorum NULL. Öte yandan, C ++ ' da yeniden boyutlandırılabilir bir bellek yığını istiyorsanız , std::vectorbunun yerine realloc... O ya da bir dosya öneririm.
otistik

19

Sorunuzu cevaplamak için ve arasındaki farkımallocnew bilmelisiniz . Fark basit:

malloc ayırır hafıza iken new ayırdığı belleğin VE yapıcı çağrıları için bellek ayrılırken ediyoruz nesnenin.

Bu nedenle, C ile sınırlı değilseniz, özellikle C ++ nesneleriyle uğraşırken asla malloc kullanmamalısınız. Bu programınızı kırmak için bir reçete olurdu.

Ayrıca arasındaki fark freeve deleteoldukça aynıdır. Fark, deletehafızayı boşaltmanın yanı sıra nesnenizin yıkıcısını çağırmasıdır.


13

mallocVe arasında büyük bir fark vardır new. mallocbellek ayırır. Bu C için iyidir, çünkü C'de bir bellek yığını bir nesnedir.

C ++ 'da, POD türleri (C türlerine benzer) ile uğraşmıyorsanız, orada gerçekten bir nesne olması için bellek konumundaki bir yapıcı çağırmalısınız. Birçok C ++ özelliği bir nesneyi otomatik olarak POD yapmadığından, P ++ dışı türler C ++ 'da çok yaygındır.

newbellek ayırır ve bu bellek konumunda bir nesne oluşturur. POD olmayan türler için bu bir kurucu çağırmak anlamına gelir.

Böyle bir şey yaparsanız:

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

Elde ettiğiniz işaretçi bir nesneye işaret etmediği için kayıttan çıkartılamaz. Kullanmadan önce üzerine bir kurucu çağırmanız gerekir (ve bu yerleşim kullanılarak yapılır new).

Öte yandan, şunları yaparsanız:

non_pod_type* p = new non_pod_type();

newBir nesne oluşturduğu için her zaman geçerli bir işaretçi elde edersiniz .

POD türleri için bile, ikisi arasında önemli bir fark vardır:

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

Tarafından oluşturulan POD nesneleri mallocbaşlatılmadığından , bu kod parçası belirtilmemiş bir değer yazdırır .

İle new, çağrılacak bir kurucu belirtebilir ve böylece iyi tanımlanmış bir değer elde edebilirsiniz.

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

Gerçekten isterseniz, newbaşlatılmamış POD nesnelerini elde etmek için kullanımı kullanabilirsiniz . Bununla ilgili daha fazla bilgi için bu diğer cevaba bakınız .

Diğer bir fark, başarısızlık üzerindeki davranıştır. Bellek mallocayıramadığında, newbir istisna atarken boş gösterici döndürür .

Birincisi, kullanmadan önce döndürülen her işaretçiyi test etmenizi gerektirir, daha sonra her zaman geçerli işaretçiler üretir.

Bu nedenlerle, C ++ kodunda kullanmalısınız new, kullanmamalısınız malloc. Ancak o zaman bile, new"açıkta" kullanmamalısınız, çünkü daha sonra bırakmanız gereken kaynakları edinir. Kullandığınızda new, sonucu hemen bir kaynak yönetim sınıfına geçirmelisiniz:

std::unique_ptr<T> p = std::unique_ptr<T>(new T()); // this won't leak

7

Dinamik ayırma yalnızca nesnenin ömrü, oluşturulduğu kapsamdan farklı olması gerektiğinde gereklidir (Bu, kapsamı küçültmek için de geçerlidir) ve değere göre depolamanın belirli bir nedeniniz varsa iş.

Örneğin:

 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);

C ++ 11'den itibaren, std::unique_ptrayrılan belleğin sahipliğini içeren ayrılan bellekle uğraşmak zorundayız . std::shared_ptrsahipliğinizi paylaşmanız gerektiğinde yaratıldı. (buna iyi bir programda beklediğinizden daha az ihtiyacınız olacaktır)

Bir örnek oluşturmak gerçekten çok kolay:

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 std::optional, bellek ayırmalarını gerektirmenizi önleyen ekler

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

'Örnek' kapsam dışına çıkar çıkmaz bellek temizlenir. Sahipliği aktarmak da kolaydır:

 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)

Peki hala ne zaman ihtiyacın var new? C ++ 11'den neredeyse hiç. Çoğunluğu, std::make_uniqueham işaretçiler aracılığıyla sahipliğini aktaran bir API'ya ulaştığınız bir noktaya ulaşıncaya kadar kullanırsınız .

 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

C ++ 98 / 03'te manuel bellek yönetimi yapmanız gerekir. Bu durumda, standardın daha yeni bir sürümüne yükseltmeyi deneyin. Sıkıştıysanız:

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

Bellek sızıntısı olmaması için sahipliği doğru takip ettiğinizden emin olun! Hareket semantiği de henüz çalışmıyor.

Peki, ne zaman C ++ 'da malloc'a ihtiyacımız var? Tek geçerli neden bellek ayırmak ve daha sonra yeni yerleştirme yoluyla başlatmak olacaktır.

 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

Yukarıdakiler geçerli olsa da, bu yeni bir operatör üzerinden de yapılabilir. std::vectorbunun için iyi bir örnek.

Son olarak, hala odasında fil var: C. Belleğin C ++ kodunda ayrıldığı ve C kodunda (veya başka bir şekilde) serbest bırakıldığı bir C kitaplığıyla çalışmak zorundaysanız, malloc / free kullanmak zorunda kalırsınız.

Bu durumda sanal işlevleri, üye işlevlerini, sınıfları unutun ... Yalnızca içinde POD bulunan yapılara izin verilir.

Kuralların bazı istisnaları:

  • Malloc'un uygun olduğu gelişmiş veri yapılarına sahip standart bir kütüphane yazıyorsunuz
  • Büyük miktarda bellek ayırmanız gerekiyor (10 GB'lik bir dosyanın bellek kopyasında mı?)
  • Belirli yapıları kullanmanızı engelleyen takımlarınız var
  • Eksik bir türü saklamanız gerekiyor

6

Bunu newyapmayan birkaç şey var malloc:

  1. new nesnenin yapıcısını çağırarak nesneyi oluşturur
  2. new ayrılan belleğin tiplendirilmesini gerektirmez.
  3. Bir miktar bellek tahsis edilmesini gerektirmez, bunun yerine bir dizi nesnenin inşa edilmesini gerektirir.

Yani, kullanırsanız malloc, o zaman yukarıdaki şeyleri açıkça yapmanız gerekir, ki bu her zaman pratik değildir. Ayrıca, newaşırı yüklenebilir ancak mallocolamaz.


5

Eğer inşaat / yıkıma ihtiyaç duymayan ve yeniden tahsis gerektiren verilerle çalışıyorsanız (örneğin, geniş bir ints dizisi), o zaman malloc / free'in size realloc verdiğinden iyi bir seçim olduğuna inanıyorum, bu da yeni memcpy'den çok daha hızlı -delete (Linux kutumda, ama sanırım bu platforma bağlı olabilir). POD olmayan ve inşaat / imha gerektiren C ++ nesneleri ile çalışıyorsanız, yeni ve silme işleçlerini kullanmanız gerekir.

Her neyse, hız artışından faydalanabiliyorsa (bazen önemli diziler, eğer büyük diziler alıyorsanız, neden her ikisini de kullanmamanız gerektiğini anlamıyorum (hatalı hafızanızı boşaltmanız ve yeni tahsis edilmiş nesneleri silmeniz koşuluyla) POD).

Gereksinim duymadığınız sürece, C ++ 'da yeni / delete komutuna bağlı kalmalısınız.


3

C ++ 'a taşımak istediğiniz C kodunuz varsa, içinde herhangi bir malloc () çağrısı bırakabilirsiniz. Herhangi bir yeni C ++ kodu için, bunun yerine yenisini kullanmanızı öneririm.


3

C ++ kullanıyorsanız, operatör oldukları için malloc / calloc yerine new / delete komutunu kullanmayı deneyin. Malloc / calloc için başka bir başlık eklemeniz gerekir. Aynı kodda iki farklı dili karıştırmayın. Çalışmaları her şekilde benzerdir, her ikisi de hash tablosundaki yığın segmentinden hafızayı dinamik olarak ayırır.


2

new yapının varsayılan değerlerini başlatır ve içindeki referansları kendisine doğru şekilde bağlar.

Örneğin

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

Böylece new struct test_s, malloc'ed sürümü varsayılan değerlere sahip değildir ve stajyer referansları başlatılmazken, çalışma referansı ile başlatılmış bir yapı döndürür.


1

Daha düşük bir perspektiften bakıldığında, yeni, belleği vermeden önce tüm belleği başlatırken malloc belleğin orijinal içeriğini koruyacaktır.


4
yenisi genel olarak belleği başlatmaz, ancak bunu yapmanın yolları vardır: bunun hakkında bir tartışma için stackoverflow.com/questions/2204176/… adresine bakın .
wjl

0

Aşağıdaki senaryoda, yapıcı çağırdığı için yeniyi kullanamayız.

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;
    }
};

0

newVe deleteoperatörler, oysa sınıflar ve yapılar üzerinde çalışabilir mallocve freeihtiyaç döküm olduğu bellek bloklarının sadece eser.

Kullanmak new/delete, gerekli veri yapısına ayrılan belleği yayınlamanız gerekmeyeceğinden kodunuzu geliştirmenize yardımcı olacaktır.


0

Yeni / delete yerine malloc / free kullanmayı düşünmek nadir bir durumdur. daha fazla C ++ yaklaşımı).


-4

Aynı çalışma c ++ 'da new () tarafından yapılırken, malloc () işlevi C'ye dinamik olarak bellek atamak için kullanılır. Böylece 2 dilden oluşan kodlama kurallarını karıştıramazsınız. Calloc ve malloc () arasındaki farkı istediyseniz iyi olur


2
Sen olabilir (ama hemen hemen her zaman olmamalıdır) kullanan mallocC ++.
interjay

1
Ayrıca, akıllı işaretçilerden geçmedikçe dinamik bellek ayırmadan kaçınmayı amaçlamanız gereken ana noktayı kaçırdınız. Diğer bilge acı için kendini
hazırlıyorsun
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.