597 Stimmen

In welchen Fällen sollte ich malloc und/oder new verwenden?

Ich sehe, dass es in C++ mehrere Möglichkeiten gibt, Daten zuzuweisen und freizugeben, und ich verstehe, dass Sie beim Aufruf von malloc sollten Sie anrufen free und wenn Sie die new Operator sollten Sie koppeln mit delete und es ist ein Fehler, die beiden zu vermischen (z.B. Aufruf von free() auf etwas, das mit dem Programm new Operator), aber ich bin mir nicht sicher, wann ich die malloc / free und wann sollte ich die new / delete in meinen Programmen der realen Welt.

Wenn Sie ein C++-Experte sind, lassen Sie mich bitte wissen, welche Faustregeln oder Konventionen Sie in dieser Hinsicht befolgen.

487voto

Brian R. Bondy Punkte 325712

Sofern Sie nicht gezwungen sind, C zu verwenden, sollten Sie niemals verwenden malloc . Immer verwenden new .

Wenn Sie eine große Menge an Daten benötigen, tun Sie einfach etwas wie:

char *pBuffer = new char[1024];

Aber Vorsicht, das ist nicht korrekt:

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

Stattdessen sollten Sie dies tun, wenn Sie ein Array von Daten löschen:

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

Le site new Schlüsselwort ist die C++-Methode, die sicherstellt, dass Ihr Typ seine Konstruktor genannt . Die new Stichwort ist auch mehr Typsicher während malloc ist überhaupt nicht typsicher.

Die einzige Möglichkeit, die ich mir vorstellen kann, ist, dass es vorteilhaft wäre, die malloc wäre, wenn Sie die Größe des Puffers ändern der Daten. Die Website new Schlüsselwort gibt es keine analoge Möglichkeit wie realloc . Die realloc Funktion kann die Größe eines Speicherabschnitts möglicherweise effizienter erweitern.

Es ist erwähnenswert, dass Sie nicht mischen können new / free y malloc / delete .

Hinweis: Einige Antworten auf diese Frage sind ungültig.

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

168voto

Flexo Punkte 84571

Die kurze Antwort lautet: Verwenden Sie nicht malloc für C++, ohne dass es dafür einen wirklich guten Grund gibt. malloc hat bei der Verwendung mit C++ eine Reihe von Mängeln, die new definiert wurde, zu überwinden.

Behebung von Mängeln durch neuen Code für C++

  1. malloc ist in keiner sinnvollen Weise typsicher. In C++ ist es erforderlich, die Rückgabe von void* . Dies kann zu einer Reihe von Problemen führen:

    #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. Aber es ist noch schlimmer. Wenn der betreffende Typ POD (einfache alte Daten) dann können Sie halbwegs vernünftig mit malloc um dafür Speicher zuzuweisen, da f2 im ersten Beispiel tut.

    Es ist allerdings nicht so offensichtlich, ob ein Typ POD ist. Die Tatsache, dass es möglich ist, dass ein bestimmter Typ von POD zu nicht-POD wechselt, ohne dass dies zu einem Compilerfehler führt, und dass es möglicherweise sehr schwer ist, Probleme zu beheben, ist ein wichtiger Faktor. Wenn zum Beispiel jemand (möglicherweise ein anderer Programmierer, während der Wartung, viel später) eine Änderung vornimmt, die Folgendes verursacht foo nicht mehr POD ist, dann würde zur Kompilierzeit kein offensichtlicher Fehler erscheinen, wie Sie hoffen würden, z.B.:

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

    würde die malloc von f2 auch schlecht werden, ohne dass es eine offensichtliche Diagnose gibt. Das Beispiel hier ist trivial, aber es ist möglich, versehentlich Nicht-PODness viel weiter weg einzuführen (z. B. in einer Basisklasse, indem ein Nicht-POD-Mitglied hinzugefügt wird). Wenn Sie C++11/boost haben, können Sie is_pod um zu überprüfen, ob diese Annahme richtig ist, und um einen Fehler zu erzeugen, wenn dies nicht der Fall ist:

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

    Obwohl der Boost nicht feststellen können, ob ein Typ POD ist ohne C++11 oder andere Compiler-Erweiterungen.

  3. malloc gibt zurück. NULL wenn die Zuweisung fehlschlägt. new wirft std::bad_alloc . Das Verhalten bei der späteren Verwendung einer NULL Zeiger ist undefiniert. Eine Ausnahme hat eine saubere Semantik, wenn sie ausgelöst wird, und sie wird von der Fehlerquelle ausgelöst. Einhüllen malloc mit einem entsprechenden Test bei jedem Aufruf erscheint mühsam und fehleranfällig. (Man muss es nur einmal vergessen, um all die gute Arbeit zunichte zu machen). Eine Ausnahme kann sich bis zu einer Ebene ausbreiten, auf der ein Aufrufer in der Lage ist, sie vernünftig zu verarbeiten, während NULL ist viel schwieriger, sinnvoll zurückzugeben. Wir könnten unsere safe_foo_malloc Funktion, um eine Ausnahme zu machen, das Programm zu beenden oder einen Handler aufzurufen:

    #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. Grundlegend malloc ist ein C-Merkmal und new ist eine C++-Funktion. Infolgedessen malloc nicht gut mit Konstruktoren zusammenarbeitet, wird nur die Zuweisung eines Byte-Stücks berücksichtigt. Wir könnten unsere safe_foo_malloc weiter zu verwenden Platzierung 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. Unser safe_foo_malloc Funktion ist nicht sehr generisch - idealerweise wollen wir etwas, das mit jedem Typ umgehen kann, nicht nur mit foo . Wir können dies mit Templates und variadischen Templates für Nicht-Standard-Konstruktoren erreichen:

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

    Durch die Behebung aller bisher festgestellten Probleme haben wir die Standardeinstellungen praktisch neu erfunden new Betreiber. Wenn Sie Folgendes verwenden malloc und Platzierung new dann können Sie genauso gut einfach new um damit zu beginnen!

59voto

Matthias Benkard Punkte 15177

Desde el C++ FQA Lite :

[16.4] Warum sollte ich new statt des vertrauenswürdige alte malloc() verwenden?

FAQ: neu/löschen Aufruf der Konstruktor/Destruktor auf; new ist typ sicher, malloc ist es nicht; new kann von einer Klasse überschrieben werden.

FQA: Die Tugenden von neu erwähnt durch FAQ erwähnten Tugenden sind keine Tugenden, weil Konstruktoren, Destruktoren und Operatorüberladung sind Müll (siehe was passiert, wenn man keine Garbage Sammlung?), und die Typsicherheit Problem ist hier wirklich winzig (normalerweise müssen Sie das void*, das von malloc zurückgegebene void* in den richtigen Zeigertyp um um es einer typisierten Zeigervariablen zuzuweisen, was lästig sein mag, aber weit entfernt von "unsicher").

Oh, und mit vertrauenswürdigen alten malloc macht es möglich, das ebenso vertrauenswürdige & alte realloc. Schade, dass wir nicht einen glänzenden neuen Operator renew oder so etwas haben.

Dennoch ist neu nicht schlimm genug, um eine Abweichung vom üblichen Stil zu rechtfertigen Stil einer Sprache zu rechtfertigen, selbst wenn die Sprache C++ ist. In Insbesondere Klassen mit nicht-trivialen Konstruktoren werden sich auf fatale Weise falsch verhalten verhalten, wenn Sie die Objekte einfach malloc laden. Warum also nicht new im gesamten Code? Leute überladen selten den Operator new überladen, also wird er Ihnen wahrscheinlich nicht nicht allzu sehr im Weg. Und wenn sie doch überladen new überladen, können Sie sie jederzeit bitten, damit aufzuhören.

Tut mir leid, ich konnte einfach nicht widerstehen :)

55voto

Ferruccio Punkte 96076

Verwenden Sie in C++ immer new. Wenn Sie einen nicht typisierten Speicherblock benötigen, können Sie den Operator new direkt verwenden:

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

52voto

Yogeesh H T Punkte 2411

new vs malloc()

1) new ist ein Betreiber , während malloc() ist eine Funktion .

2) new ruft auf. Konstrukteure , während malloc() nicht.

3) new gibt zurück. genauer Datentyp , während malloc() gibt zurück. void * .

4) new gibt niemals eine NULL (wird bei Fehlschlag geworfen), während malloc() gibt NULL zurück

5) Neuzuweisung von Speicher, der nicht von new während malloc() puede

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X