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


479

Ich sehe in C ++, dass es mehrere Möglichkeiten gibt, Daten zuzuweisen und freizugeben, und ich verstehe, dass Sie beim Aufrufen anrufen mallocsollten freeund wenn Sie den newOperator verwenden, mit dem Sie koppeln sollten, deleteund es ein Fehler ist, die beiden zu mischen (z. B. Aufrufen free()von etwas, das erstellt wurde mit dem newOperator), aber mir ist nicht klar, wann ich malloc/ freeund wann ich new/ deletein meinen realen Programmen verwenden soll.

Wenn Sie ein C ++ - Experte sind, teilen Sie mir bitte die Faustregeln oder Konventionen mit, die Sie in dieser Hinsicht befolgen.


33
Ich möchte nur eine Erinnerung hinzufügen, dass Sie die beiden Stile nicht mischen können - das heißt, Sie können weder new verwenden, um ein Objekt zu erstellen und dann free () darauf aufzurufen, noch versuchen, einen von malloc () zugewiesenen Block zu löschen. Wahrscheinlich offensichtlich, um es zu sagen, aber trotzdem ...
nsayer

32
Gute Antworten, alles was ich hinzufügen muss (was ich nicht gesehen habe) ist, dass new / delete den Konstruktor / Destruktor für Sie aufruft, malloc / free nicht. Nur ein erwähnenswerter Unterschied.
Bill K

Mit modernem C ++ versuche ich immer noch, einen Grund dafür zu finden.
Rahly

Oder verwenden Sie keine und gehen Sie mit std: shared_ptr <T>. Dann müssen Sie überhaupt nicht löschen.
Vincent

Antworten:


387

Wenn Sie nicht gezwungen sind, C zu verwenden, sollten Sie es niemals verwenden malloc . Immer benutzen new.

Wenn Sie einen großen Datenblock benötigen, gehen Sie einfach wie folgt vor:

char *pBuffer = new char[1024];

Seien Sie vorsichtig, obwohl dies nicht korrekt ist:

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

Stattdessen sollten Sie dies tun, wenn Sie ein Datenarray löschen:

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

Das newSchlüsselwort ist die C ++ - Methode und stellt sicher, dass der Konstruktor Ihres Typs aufgerufen wird . Das newSchlüsselwort ist außerdem typsicherer, während malloces überhaupt nicht typsicher ist.

Ich könnte mir nur vorstellen, dass dies von Vorteil ist, mallocwenn Sie die Größe Ihres Datenpuffers ändern müssen . Das newSchlüsselwort hat keine analoge Art wie realloc. Die reallocFunktion kann möglicherweise die Größe eines Speicherblocks für Sie effizienter erweitern.

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

Hinweis: Einige Antworten in dieser 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

2
In Bezug auf den Aufruf von delete foo, wenn Sie delete [] foo aufrufen sollten, werden einige Compiler dies automatisch für Sie beheben und nicht lecken, und andere löschen nur den ersten Eintrag und das Leck. Ich hatte einige davon in einem Code und Valgrind wird sie für Sie finden.
KPexEA

30
Wenn Sie nicht das richtige Löschen verwenden, ist das Ergebnis undefiniert . Es ist falsch. Die Tatsache, dass es manchmal einen Teil der Sache richtig macht oder funktioniert, ist nur blindes Glück.
Michael Burr

8
@KPexEA: Auch wenn einige Compiler Ihre Fehler beheben könnten, ist es immer noch falsch, sie an erster Stelle zu machen :) Verwenden Sie gegebenenfalls immer delete [].
Korona

62
"Wenn Sie nicht gezwungen sind, C zu verwenden, sollten Sie niemals malloc verwenden. Verwenden Sie immer new." Warum? Was ist der Gewinn hier? Für Objekte, die wir konstruieren müssen, aber für Speicherblöcke dokumentieren Sie klar zwei Möglichkeiten, um Codierungsfehler zu machen (das leichter abgefangene () vs [] in neu und das weniger leicht abgefangene nicht übereinstimmende Array vs scaler neu und löschen). Was ist die Motivation für die Verwendung von new / delete für Blöcke von Rohspeicher?
Ben Supnik

3
@DeadMG: Wenn man ein Array zur Verwendung durch eine asynchrone API-Funktion erstellt, wäre das nicht new[]viel sicherer als std::vector? Wenn man verwendet new[], würde der Zeiger nur über explizit ungültig werden delete, während der für a zugewiesene Speicher std::vectorungültig werden könnte, wenn die Größe des Vektors geändert wird oder der Gültigkeitsbereich verlassen wird. (Beachten Sie, dass bei Verwendung new[]die Möglichkeit deleteberücksichtigt werden muss, dass möglicherweise nicht aufgerufen werden kann, wenn die asynchrone Methode noch aussteht. Wenn eine asynchrone Operation abgebrochen werden muss, muss möglicherweise das Löschen per Rückruf veranlasst werden.) .
Supercat

144

Die kurze Antwort lautet: Verwenden Sie mallocC ++ nicht ohne einen wirklich guten Grund dafür. mallochat eine Reihe von Mängeln bei der Verwendung mit C ++, die newdefiniert wurden, um zu überwinden.

Durch C ++ - Code neu behobene Mängel

  1. mallocist in keiner sinnvollen Weise typsicher. In C ++ müssen Sie die Rückgabe von umwandeln void*. Dies führt möglicherweise zu vielen Problemen:

    #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. Es ist schlimmer als das. Wenn es sich bei dem fraglichen Typ um POD (einfache alte Daten) handelt , können Sie mallocihn wie f2im ersten Beispiel halbwegs sinnvoll verwenden , um Speicher zuzuweisen .

    Es ist jedoch nicht so offensichtlich, ob ein Typ POD ist. Die Tatsache, dass es für einen bestimmten Typ möglich ist, von POD zu Nicht-POD zu wechseln, ohne dass ein Compilerfehler auftritt und möglicherweise sehr schwer zu debuggen ist, ist ein wesentlicher Faktor. Wenn zum Beispiel jemand (möglicherweise ein anderer Programmierer) während der Wartung viel später eine Änderung vornehmen würde, die foodazu führte , dass kein POD mehr vorhanden war, würde beim Kompilieren kein offensichtlicher Fehler auftreten, wie Sie hoffen würden, z.

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

    würde das machen mallocvon f2auch schlecht werden , ohne offensichtliche Diagnose. Das Beispiel hier ist trivial, aber es ist möglich, versehentlich Nicht-PODness viel weiter entfernt 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überprüfen, ob diese Annahme korrekt ist, und einen Fehler 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)));
    }

    Boost kann zwar nicht feststellen, ob ein Typ POD ohne C ++ 11 oder andere Compiler-Erweiterungen ist.

  3. mallocGibt zurück, NULLwenn die Zuordnung fehlschlägt. newwird werfen std::bad_alloc. Das Verhalten der späteren Verwendung eines NULLZeigers ist undefiniert. Eine Ausnahme hat eine saubere Semantik, wenn sie ausgelöst wird und von der Fehlerquelle ausgelöst wird. Das Umschließen mallocmit einem geeigneten Test bei jedem Anruf erscheint mühsam und fehleranfällig. (Sie müssen nur einmal vergessen, um all diese gute Arbeit rückgängig zu machen). Eine Ausnahme kann sich auf eine Ebene ausbreiten, auf der ein Anrufer sie sinnvoll verarbeiten kann, wobei NULLes viel schwieriger ist, sie sinnvoll zurückzugeben. Wir könnten unsere safe_foo_mallocFunktion erweitern, um eine Ausnahme auszulösen oder 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. Grundsätzlich mallochandelt es sich um eine C-Funktion und neweine C ++ - Funktion. Infolgedessen mallocspielt es mit Konstruktoren nicht gut, sondern es wird nur ein Teil der Bytes zugewiesen. Wir könnten unsere safe_foo_mallocPlatzierung weiter ausbauen , um die Platzierung zu nutzen 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. Unsere safe_foo_mallocFunktion ist nicht sehr allgemein gehalten - im Idealfall möchten wir etwas, das für jeden Typ geeignet ist, nicht nur foo. Dies können wir mit Vorlagen und variadischen Vorlagen für nicht standardmäßige 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)...);
      }
    };

    Bei der Behebung aller bisher identifizierten Probleme haben wir den Standardoperator praktisch neu erfunden new. Wenn Sie verwenden mallocund platzieren möchten, können newSie es auch gleich verwenden new!


27
Es ist schade, dass C ++ gemacht wurde structund im classGrunde dasselbe bedeutet. Ich frage mich, ob es Probleme gegeben structhätte, für PODs reserviert zu sein und möglicherweise davon auszugehen, dass alle classTypen Nicht-PODs sind. Alle durch Code definierten Typen, die vor der Erfindung von C ++ definiert wurden, wären notwendigerweise PODs, daher würde ich nicht denken, dass die Abwärtskompatibilität dort ein Problem darstellen würde. Gibt es Vorteile nicht-PODs Typen mit deklarierten als structstatt class?
Supercat

1
@supercat Ein bisschen spät, aber wie sich herausstellte, war es eine wunderbare Designentscheidung, fast dasselbe zu machen structund zu classtun, die jetzt eine nette Funktion namens "Metaclasses" (von Herb) ermöglicht .
Rakete1111

@ Rakete1111: Auf den ersten Blick sieht dieser Vorschlag so aus, als würde er eine Version der Sprache vorverarbeiten, die Schlüsselwörter mit Dollar-Präfix wie verwendet $class. Ich bin mir jedoch nicht sicher, was das damit zu tun hat classund was structSynonyme sind.
Supercat

@supercat Das Typsystem wäre mehr gegabelt worden. Wenn Sie dasselbe haben classund structeffektiv bedeuten, können Sie beliebige Transformationen an ihnen durchführen ( $class), ohne sich Gedanken über ein classa machen zu müssen structund umgekehrt.
Rakete1111

@ Rakete1111: Wenn bestimmte Arten von Operationen und Transformationen bei einigen Typen sicher sind, bei anderen jedoch nicht, erscheint es besser, wenn der Typ dies direkt identifiziert und ein Compiler unsichere Operationen und Transformationen ablehnt, als wenn eine Metaklasse geändert wird, in der verwendet wurde Wege, die nur für einen PODS geeignet sind, werden stillschweigend in einen Nicht-PODS geändert.
Supercat

53

Aus dem C ++ FQA Lite :

[16.4] Warum sollte ich neue anstelle von vertrauenswürdigen alten malloc () verwenden?

FAQ: new / delete ruft den Konstruktor / Destruktor auf; neu ist typsicher, malloc nicht; new kann von einer Klasse überschrieben werden.

FQA: Die in den FAQ erwähnten Vorteile von Neu sind keine Vorteile, da Konstruktoren, Destruktoren und Operatorüberladung Müll sind (siehe, was passiert, wenn Sie keine Speicherbereinigung haben?), Und das Problem mit der Typensicherheit hier sehr gering ist (normalerweise haben Sie dies die von malloc zurückgegebene Leere * in den richtigen Zeigertyp umzuwandeln, um sie einer typisierten Zeigervariablen zuzuweisen, was zwar ärgerlich, aber alles andere als "unsicher" ist).

Oh, und die Verwendung eines vertrauenswürdigen alten Mallocs ermöglicht die Verwendung des gleichermaßen vertrauenswürdigen und alten Reallocs. Schade, dass wir keinen glänzenden neuen Operator erneuern oder so.

Trotzdem ist neu nicht schlecht genug, um eine Abweichung von dem in einer Sprache üblichen Stil zu rechtfertigen, selbst wenn die Sprache C ++ ist. Insbesondere Klassen mit nicht trivialen Konstruktoren verhalten sich auf fatale Weise schlecht, wenn Sie die Objekte einfach mallocieren. Warum also nicht im gesamten Code neu verwenden? Die Leute überladen den Bediener selten neu, so dass er Ihnen wahrscheinlich nicht zu sehr im Weg steht. Und wenn sie neue überladen, können Sie sie jederzeit bitten, aufzuhören.

Entschuldigung, ich konnte einfach nicht widerstehen. :) :)


7
Das ist ein Aufstand ! Vielen Dank.
dmckee --- Ex-Moderator Kätzchen

8
Ich kann diesen Kommentar nicht ernst nehmen, da er eindeutig die Voreingenommenheit des Autors gegenüber C ++ projiziert. C ++ ist eine Sprache, mit der leistungsorientierte Software erstellt wird, und ein Garbage Collector kann sich nur nachteilig auf sein Ziel auswirken. Ich bin mit Ihrer gesamten Antwort nicht einverstanden!
Miguel

1
@ Miguel Du hast den Witz verpasst.
Dan Bechard

50

Verwenden Sie in C ++ immer new. Wenn Sie einen Block untypisierten Speichers benötigen, können Sie den Operator new direkt verwenden:

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

3
Interessanterweise habe ich immer nur ein Array von Zeichen ohne Vorzeichen zugewiesen, wenn ich einen solchen Rohdatenpuffer benötige.
Greg Rogers

Vorsicht, die Semmantics sollten folgendermaßen aussehen: p_var = neuer Typ (Initialisierer); Nicht Größe.
Brian R. Bondy

11
Nicht wenn Sie den Operator new direkt aufrufen, wird die Anzahl der zuzuweisenden Bytes als Parameter benötigt.
Ferruccio

1
Hrm nicht sicher, ich habe noch nie von dieser Syntax gehört.
Brian R. Bondy

9
Das Gegenteil von operator newist operator delete. Es ist keine genau definierte Aktion, deleteeinen Ausdruck mit Typ aufzurufen void*.
CB Bailey

33

Verwendung mallocund nur zum Zuweisen von Speicher, der von c-zentrierten Bibliotheken und APIs verwaltet werden soll. Verwenden Sie und (und die Varianten) für alles, was Sie steuern.free newdelete[]


10
Beachten Sie auch, dass eine gut geschriebene C-Bibliothek malloc versteckt und intern frei ist. So sollte der C-Programmierer arbeiten.
Dacav

@dmckee Haben Sie ein Beispiel für C ++ mit c-zentrierten Bibliotheken von malloc und free?
Meilenma

1
@Dacav: Wenn eine C-Funktion einen Zeiger auf ein Objekt akzeptiert, das sie nach der Rückkehr der Funktion weiter verwenden muss, und der Aufrufer nicht wissen kann, wann das Objekt noch benötigt wird, ist dies für die Funktion durchaus sinnvoll um anzugeben, dass der Zeiger mit erstellt worden sein muss malloc. Wenn eine Funktion wie strdupein Objekt erstellen und an einen Aufrufer zurückgeben muss, ist es durchaus sinnvoll anzugeben, dass der Aufrufer freedas Objekt aufrufen muss, wenn es nicht mehr benötigt wird. Wie könnten solche Funktionen vermeiden, dass sie dem Anrufer ihre Verwendung von malloc / free aussetzen?
Supercat

@supercat, es ist von Natur aus falsch, wenn eine C-Funktion einen Zeiger auf Objekte akzeptiert, da C Objekte überhaupt nicht kennt. Im Allgemeinen glaube ich, dass der beste Ansatz darin besteht, semantische Wrapper für die Zuweisung / Freigabe auch in C zu haben. Es kann immer noch akzeptabel, aber weniger flexibel sein, wenn eine C-Bibliothek den Aufrufer auffordert, Speicher vorab zuzuweisen und / oder freizugeben. Wenn eine C-Funktion dies tut und den Besitz des zugewiesenen Speichers beansprucht, müssen Sie ihn implizit malloc zuweisen.
Dacav

@supercat Ein Beispiel für ein tägliches Paket, das sicher jeder verwendet hat, ist libgmp. Wenn Sie jemals eine Open-Source-Verschlüsselung oder Software verwendet haben, die auf einer solchen Verschlüsselung basiert (was sehr wahrscheinlich ist), haben Sie wahrscheinlich eine Arithmetikbibliothek mit beliebiger Genauigkeit verwendet, die ihre eigenen internen Daten vergrößern und verkleinern muss. Dies geschieht mit einer Initialisierungsfunktion ... und dann müssen Sie sich fragen, wie Sie den C-Code libgmp in C ++ verwenden, ohne ihn in C ++ neu zu kompilieren. Jetzt mit dieser (der Linker) im Sinn, darüber nachzudenken ... warum sollte jeder vernünftige Mensch jemals setzen mallocin C ++?
autistisch

31

neu gegen malloc ()

1) newist ein Operator , während malloc()es sich um eine Funktion handelt .

2) newruft Konstruktoren auf , während malloc()dies nicht der Fall ist.

3) newliefert genauen Datentyp , während malloc()kehrt void * .

4) gibt newniemals NULL zurück (wird bei einem Fehler malloc()ausgelöst ), während NULL zurückgegeben wird

5) Neuzuweisung von Speicher, der nicht von newwhile malloc()can verarbeitet wird


6
Hallo, für Punkt 4) kann new angewiesen werden, bei einem Fehler NULL zurückzugeben. char* ptr = new (std::nothrow) char [323232];
Singh

1
6) new erstellt aus Konstruktorargumenten, während malloc size verwendet.
Evan Moran

Es gibt auch eine newFunktion
Ma Ming

Wenn Sie so in C zu geneigt waren Umspeichern , würde ich hoffen , dass Sie verwenden würden , reallocanstatt malloc, und mit dem Zeigervariable beginnen initialisiert NULL. Wenn Sie andererseits einen veränderbaren Speicherblock in C ++ möchten , würde ich vorschlagen, std::vectorim Gegensatz zu realloc... dem oder einer Datei.
autistisch

19

Um Ihre Frage zu beantworten, sollten Sie den Unterschied zwischen mallocund kennennew . Der Unterschied ist einfach:

malloc weist Speicher zu , während new Speicher zuweist UND den Konstruktor des Objekts aufruft, für das Sie Speicher zuweisen .

Wenn Sie also nicht auf C beschränkt sind, sollten Sie malloc niemals verwenden, insbesondere wenn Sie mit C ++ - Objekten arbeiten. Das wäre ein Rezept, um Ihr Programm zu brechen.

Auch der Unterschied zwischen freeund deleteist ziemlich gleich. Der Unterschied besteht darin, dass deletezusätzlich zur Speicherfreigabe der Destruktor Ihres Objekts aufgerufen wird.


13

Es gibt einen großen Unterschied zwischen mallocund new. mallocordnet Speicher zu. Dies ist für C in Ordnung, da in C ein Speicherklumpen ein Objekt ist.

Wenn Sie in C ++ nicht mit POD-Typen (die C-Typen ähnlich sind) arbeiten, müssen Sie einen Konstruktor an einem Speicherort aufrufen, um tatsächlich ein Objekt dort zu haben. Nicht-POD-Typen sind in C ++ sehr verbreitet, da viele C ++ - Funktionen ein Objekt automatisch zu einem Nicht-POD machen.

newweist Speicher zu und erstellt ein Objekt an diesem Speicherort. Für Nicht-POD-Typen bedeutet dies, einen Konstruktor aufzurufen.

Wenn Sie so etwas tun:

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

Der Zeiger, den Sie erhalten, kann nicht dereferenziert werden, da er nicht auf ein Objekt zeigt. Sie müssen einen Konstruktor darauf aufrufen, bevor Sie ihn verwenden können (und dies erfolgt mithilfe der Platzierung new).

Wenn Sie andererseits Folgendes tun:

non_pod_type* p = new non_pod_type();

Sie erhalten einen Zeiger, der immer gültig ist, weil newein Objekt erstellt wurde.

Selbst für POD-Typen gibt es einen signifikanten Unterschied zwischen den beiden:

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

Dieser Code würde einen nicht angegebenen Wert ausgeben, da die von erstellten POD-Objekte mallocnicht initialisiert werden.

Mit newkönnen Sie einen Konstruktor angeben, der aufgerufen werden soll, und so einen genau definierten Wert erhalten.

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

Wenn Sie es wirklich wollen, können Sie es verwenden new, um nicht initialisierte POD-Objekte zu erhalten. Weitere Informationen hierzu finden Sie in dieser anderen Antwort .

Ein weiterer Unterschied ist das Verhalten bei einem Ausfall. Wenn kein Speicher zugewiesen werden kann, wird mallocein Nullzeiger zurückgegeben, während neweine Ausnahme ausgelöst wird.

Ersteres erfordert, dass Sie jeden zurückgegebenen Zeiger testen, bevor Sie ihn verwenden, während letzteres immer gültige Zeiger erzeugt.

Aus diesen Gründen sollten Sie in C ++ - Code verwenden newund nicht malloc. Aber selbst dann sollten Sie nicht new"im Freien" verwenden, da es Ressourcen beschafft, die Sie später freigeben müssen. Wenn Sie verwenden new, sollten Sie das Ergebnis sofort an eine Ressourcenverwaltungsklasse übergeben:

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

7

Eine dynamische Zuordnung ist nur erforderlich, wenn die Lebensdauer des Objekts von dem Bereich abweichen soll, in dem es erstellt wird (dies gilt auch, um den Bereich kleiner als größer zu machen) und Sie einen bestimmten Grund haben, warum das Speichern nach Wert dies nicht tut Arbeit.

Zum Beispiel:

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

Ab C ++ 11 müssen wir uns std::unique_ptrmit dem zugewiesenen Speicher befassen, der den Besitz des zugewiesenen Speichers enthält. std::shared_ptrwurde erstellt, wenn Sie das Eigentum teilen müssen. (Sie benötigen dies weniger als Sie in einem guten Programm erwarten würden)

Das Erstellen einer Instanz wird ganz einfach:

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 fügt außerdem hinzu, std::optionalwodurch verhindert werden kann, dass Speicherzuordnungen erforderlich sind

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

Sobald 'Instanz' den Gültigkeitsbereich verlässt, wird der Speicher bereinigt. Die Übertragung des Eigentums ist auch einfach:

 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)

Wann brauchen Sie noch new? Fast nie ab C ++ 11. Die meisten davon verwenden Sie, std::make_uniquebis Sie zu einem Punkt gelangen, an dem Sie auf eine API stoßen, die den Besitz über Rohzeiger überträgt.

 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

In C ++ 98/03 müssen Sie die manuelle Speicherverwaltung durchführen. In diesem Fall versuchen Sie, ein Upgrade auf eine neuere Version des Standards durchzuführen. Wenn Sie nicht weiterkommen:

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

Stellen Sie sicher, dass Sie den Besitz korrekt verfolgen, um keine Speicherlecks zu haben! Die Bewegungssemantik funktioniert auch noch nicht.

Wann brauchen wir Malloc in C ++? Der einzig gültige Grund wäre, Speicher zuzuweisen und ihn später durch Platzierung neu zu initialisieren.

 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

Obwohl das oben Gesagte gültig ist, kann dies auch über einen neuen Operator erfolgen. std::vectorist ein gutes Beispiel dafür.

Endlich haben wir noch den Elefanten im Raum : C. Wenn Sie mit einer C-Bibliothek arbeiten müssen, in der Speicher im C ++ - Code zugewiesen und im C-Code freigegeben wird (oder umgekehrt), müssen Sie malloc / free verwenden.

Wenn Sie in diesem Fall sind, vergessen Sie virtuelle Funktionen, Elementfunktionen, Klassen ... Nur Strukturen mit PODs sind zulässig.

Einige Ausnahmen von den Regeln:

  • Sie schreiben eine Standardbibliothek mit erweiterten Datenstrukturen, in denen malloc angemessen ist
  • Sie müssen große Speichermengen zuweisen (In der Speicherkopie einer 10-GB-Datei?)
  • Sie haben Werkzeuge, die Sie daran hindern, bestimmte Konstrukte zu verwenden
  • Sie müssen einen unvollständigen Typ speichern

6

Es gibt ein paar Dinge, die newdas mallocnicht tun:

  1. new Konstruiert das Objekt durch Aufrufen des Konstruktors dieses Objekts
  2. new erfordert keine Typumwandlung des zugewiesenen Speichers.
  3. Es muss nicht genügend Speicher zugewiesen werden, sondern es müssen mehrere Objekte erstellt werden.

Wenn Sie also verwenden malloc, müssen Sie die oben genannten Dinge explizit ausführen, was nicht immer praktisch ist. Darüber hinaus newkann überlastet werden, mallockann aber nicht sein.


5

Wenn Sie mit Daten arbeiten, die nicht erstellt / zerstört werden müssen und eine Neuzuweisung erfordern (z. B. eine große Anzahl von Ints), ist malloc / free meiner Meinung nach eine gute Wahl, da Sie eine Neuzuweisung erhalten, die viel schneller ist als new-memcpy -delete (es ist auf meiner Linux-Box, aber ich denke, dies kann plattformabhängig sein). Wenn Sie mit C ++ - Objekten arbeiten, die kein POD sind und eine Konstruktion / Zerstörung erfordern, müssen Sie die Operatoren new und delete verwenden.

Wie auch immer, ich verstehe nicht, warum Sie nicht beide verwenden sollten (vorausgesetzt, Sie geben Ihren Speicher frei und löschen mit neu zugewiesene Objekte), wenn Sie den Geschwindigkeitsschub nutzen können (manchmal einen signifikanten, wenn Sie große Arrays neu zuweisen von POD), die Realloc Ihnen geben kann.

Sofern Sie es nicht benötigen, sollten Sie sich in C ++ an new / delete halten.


3

Wenn Sie C-Code haben, den Sie nach C ++ portieren möchten, können Sie alle malloc () -Aufrufe darin belassen. Für jeden neuen C ++ - Code würde ich empfehlen, stattdessen new zu verwenden.


3

Wenn Sie C ++ verwenden, versuchen Sie, new / delete anstelle von malloc / calloc zu verwenden, da es sich um Operatoren handelt. Für malloc / calloc müssen Sie einen weiteren Header einfügen. Mischen Sie nicht zwei verschiedene Sprachen im selben Code. Ihre Arbeit ist in jeder Hinsicht ähnlich, beide ordnen Speicher dynamisch aus dem Heap-Segment in der Hash-Tabelle zu.


2

new initialisiert die Standardwerte der Struktur und verknüpft die darin enthaltenen Referenzen korrekt mit sich selbst.

Z.B

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

Es new struct test_swird also eine initialisierte Struktur mit einer Arbeitsreferenz zurückgegeben, während die malloc'ed-Version keine Standardwerte hat und die internen Referenzen nicht initialisiert sind.


1

Aus einer niedrigeren Perspektive initialisiert new den gesamten Speicher, bevor der Speicher übergeben wird, während malloc den ursprünglichen Inhalt des Speichers beibehält.


4
new initialisiert den Speicher im Allgemeinen nicht, obwohl es Möglichkeiten gibt, dies zu erreichen: Eine Diskussion hierzu finden Sie unter stackoverflow.com/questions/2204176/… .
wjl

0

Im folgenden Szenario können wir new nicht verwenden, da es den Konstruktor aufruft.

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

Die newund deleteBetreiber können auf Klassen arbeiten und Strukturen, während mallocund freenur Arbeit mit Blöcken des Speichers, muß gegossen werden.

Die Verwendung new/deletehilft dabei, Ihren Code zu verbessern, da Sie den zugewiesenen Speicher nicht in die erforderliche Datenstruktur umwandeln müssen.


0

In seltenen Fällen sollten Sie die Verwendung von malloc / free anstelle von new / delete in Betracht ziehen, wenn Sie mit realloc zuweisen und dann neu zuweisen (einfache Pod-Typen, keine Objekte), da es in C ++ keine ähnliche Funktion wie realloc gibt (obwohl dies mit a möglich ist mehr C ++ Ansatz).


-4

malloc () wird verwendet, um Speicher in C dynamisch zuzuweisen, während new () in c ++ dieselbe Arbeit erledigt. Sie können also keine Codierungskonventionen von 2 Sprachen mischen. Es wäre gut, wenn Sie nach dem Unterschied zwischen calloc und malloc fragen würden ()


2
Sie können (sollten aber fast immer nicht) mallocin C ++ verwenden.
Interjay

1
Sie haben auch den Hauptpunkt verpasst, den Sie vermeiden sollten, um eine dynamische Speicherzuweisung zu vermeiden, es sei denn, Sie tun dies durch intelligente Zeiger. Sie
bereiten
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.