Dans quels cas dois-je utiliser malloc vs nouvelle?

je vois dans C++ qu'il y a plusieurs façons d'allouer et de libérer des données et je comprends que lorsque vous appelez malloc vous devez appeler free et lorsque vous utilisez l'opérateur new vous devez jumeler avec delete et c'est une erreur de mélanger les deux (par exemple appeler free() sur quelque chose qui a été créé avec l'opérateur new ), mais je ne suis pas clair sur quand je devrais utiliser malloc / free et quand je devrais utiliser new / delete dans mon réel world programmes de.

si vous êtes un expert en C++, veuillez me faire part de toute règle empirique ou convention que vous suivez à cet égard.

386
demandé sur Unihedron 2008-10-08 23:47:55

18 réponses

sauf si vous êtes forcé d'utiliser C, vous devez ne jamais utiliser malloc . Toujours utiliser new .

si vous avez besoin d'un gros morceau de données juste faire quelque chose comme:

char *pBuffer = new char[1024];

attention bien que ce ne soit pas correct:

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

à la place, vous devriez faire ceci en supprimant un tableau de données:

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

le mot-clé new est la façon de le faire, et il assurera que votre type aura son constructeur appelé . Le mot-clé new est aussi plus type-safe tandis que malloc n'est pas du tout type-safe.

le seul moyen que je pourrais penser que ce serait bénéfique d'utiliser malloc serait si vous aviez besoin de changer la taille de votre tampon de données. Le mot-clé new n'a pas une manière analogue comme realloc . La fonction realloc pourrait être capable d'étendre la taille d'un morceau de mémoire pour vous plus efficacement.

il est important de mentionner que vous ne pouvez pas mélanger new / free et malloc / delete .

Note: certaines réponses à cette question sont invalides.

int* p_scalar = new int(5);  // Does not create 5 elements, but initializes to 5
int* p_array  = new int[5];  // Creates 5 elements
322
répondu Brian R. Bondy 2018-07-03 00:10:31

la réponse courte est: n'utilisez pas malloc pour C++ sans une bonne raison de le faire. malloc a un certain nombre de défauts lorsqu'il est utilisé avec C++, qui new a été défini pour surmonter.

déficiences corrigées par le nouveau code C++

  1. malloc n'est pas typesafe de façon significative. En C++, vous devez lancer le retour de void* . Cela introduit potentiellement beaucoup de problèmes:

    #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. c'est pire que ça. Si le type en question Est POD (plain old data) alors vous pouvez semi-judicieusement utiliser malloc pour lui attribuer de la mémoire, comme f2 le fait dans le premier exemple.

    ce n'est pas si évident si un type est POD. Le fait qu'il soit possible pour un type donné de passer de POD à non-POD avec aucune erreur de compilateur en résultant et potentiellement très difficile à déboguer des problèmes est un facteur important. Par exemple, si quelqu'un (peut-être un autre programmeur, au cours de la maintenance, beaucoup plus tard devait faire un changement qui a fait que foo ne soit plus POD, alors aucune erreur évidente n'apparaîtrait au moment de la compilation comme vous l'espérez, par exemple:

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

    aurait fait le malloc de f2 aussi devenir mauvais, sans aucun diagnostic évident. L'exemple ici est trivial, mais il est possible de accidentellement introduire la non-Podeur beaucoup plus loin (par exemple dans une classe de base, en ajoutant un membre non-POD). Si vous avez C++11/boost vous pouvez utiliser is_pod pour vérifier que cette hypothèse est correcte et produire une erreur si elle n'est pas:

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

    bien que boost soit incapable de déterminer si un type est POD sans C++11 ou quelques autres extensions de compilateur.

  3. malloc retourne NULL si la répartition échoue. new lancera std::bad_alloc . Le comportement de l'utilisation ultérieure d'un pointeur NULL n'est pas défini. Une exception a une sémantique propre quand elle est jetée et elle est jetée de la source de l'erreur. Envelopper malloc avec un test approprié à chaque appel semble fastidieux et sujet aux erreurs. (Il suffit d'oublier une fois pour défaire tout ce bon travail). Une exception peut être autorisée pour se propager à un niveau où un appelant est capable de le traiter raisonnablement, où comme NULL est beaucoup plus difficile à transmettre de façon significative. Nous pourrions étendre notre fonction safe_foo_malloc pour lancer une exception ou quitter le programme ou appeler un gestionnaire:

    #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. fondamentalement malloc est une caractéristique C et new est une caractéristique C++. En conséquence malloc ne joue pas très bien avec les constructeurs, il ne s'agit que d'allouer un morceau d'octets. Nous pourrions étendre notre safe_foo_malloc plus d'utiliser le placement 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. notre fonction safe_foo_malloc n'est pas très générique - idéalement nous voulons quelque chose qui peut gérer n'importe quel type, pas seulement foo . Nous pouvons y parvenir avec des gabarits et des gabarits variadiques pour les constructeurs non par défaut:

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

    maintenant, en corrigeant tous les problèmes que nous avons identifiés jusqu'à présent, nous avons pratiquement réinventé l'opérateur par défaut new . Si vous utilisez malloc et de placement new , alors vous pourriez aussi bien utiliser new pour commencer!

116
répondu Flexo 2017-05-23 12:18:26

From the C++ FQA Lite :

[16.4] Pourquoi devrais-je utiliser le nouveau au lieu du digne de confiance ancien malloc()?

FAQ: Nouveau / supprimer constructeur / destructeur; type is nouveau sûr, malloc n'est pas; nouveau peut être remplacée par une classe.

FQA: les vertus de la nouvelle mentionnée par les FAQ ne sont pas des vertus, parce que les constructeurs, destructeurs, et la surcharge de l'opérateur est un déchet (voir ce qui se passe quand vous n'avez pas de déchets collection?), et le type de sécurité question est vraiment minuscule ici (normalement vous devez jeter le vide* retourné par malloc au type pointeur droit pour assignez-le à une variable de pointeur dactylographiée, ce qui peut être gênant, mais loin d' "dangereux.)"

Oh, et digne de confiance en utilisant de vieux malloc permet d'utiliser le même digne de confiance & Vieux realloc. Dommage que nous Je n'ai pas de nouvel opérateur brillant ou quelque chose comme ça.

encore, Nouveau n'est pas assez mauvais pour justifier une déviation par rapport au style utilisé dans toute une langue, même lorsque la langue est le C++. Dans en particulier, les classes non triviale les constructeurs vont mal se comporter dans fatal façons si vous malloc simplement les objets. Alors pourquoi ne pas utiliser new tout au long de la code? Les gens surchargent rarement l'opérateur neuf, donc il ne sera probablement pas dans votre de façon trop. Et si ils ne surcharge de nouvelles, vous pouvez toujours leur demander d'arrêter.

Désolé, je n'ai pas pu résister. :)

48
répondu Matthias Benkard 2008-10-08 20:24:37

utilise toujours new en C++. Si vous avez besoin d'un bloc de mémoire non typé, vous pouvez utiliser l'opérateur new directement:

void *p = operator new(size);
   ...
operator delete(p);
46
répondu Ferruccio 2008-10-09 10:05:46

utiliser malloc et free seulement pour allouer la mémoire qui va être gérée par les bibliothèques C-centric et les API. Utiliser new et delete (et les [] variantes) pour tout ce que vous contrôlez.

27
répondu dmckee 2008-10-08 20:01:38

nouvelle vs malloc()

1) new est un opérateur , tandis que malloc() est une fonction .

2) new appelle constructeurs , tandis que malloc() ne l'appelle pas.

3) new renvoie type de données exactes , tandis que malloc() renvoie void * .

4) new ne renvoie jamais un nul (sera jeté sur l'échec) tandis que malloc() renvoie nul

5) réallocation de la mémoire non traitée par new tandis que malloc() can

21
répondu Yogeesh H T 2015-11-26 10:06:05

pour répondre à votre question, vous devez connaître la différence entre malloc et new . La différence est simple:

malloc alloue de la mémoire , tandis que new alloue de la mémoire ET appelle le constructeur de l'objet de l'allocation de mémoire pour.

donc, à moins que vous ne soyez limité à C, vous ne devriez jamais utiliser malloc, en particulier quand vous négociez avec des objets en C++. Ce serait une recette pour briser votre programme.

la différence entre free et delete est la même. La différence est que delete appellera le destructeur de votre objet en plus de libérer la mémoire.

9
répondu The Quantum Physicist 2017-08-25 09:31:24

il y a une grande différence entre malloc et new . malloc attribue la mémoire. C'est très bien pour C, parce qu'en C, un morceau de mémoire est un objet.

en C++, si vous n'avez pas affaire à des types de POD (qui sont similaires aux types C), vous devez appeler un constructeur sur un emplacement de mémoire pour y avoir réellement un objet. Les types Non-POD sont très courants en C++, car de nombreuses fonctionnalités de C++ rendent un objet automatiquement non-POD.

new alloue de la mémoire et crée un objet sur cet emplacement de la mémoire. Pour les types non-POD cela signifie appeler un constructeur.

Si vous faites quelque chose comme cela:

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

le pointeur que vous obtenez ne peut pas être déréférencé car il ne pointe pas vers un objet. Vous devez appeler un constructeur dessus avant de pouvoir l'utiliser (et ceci est fait en utilisant le placement new ).

si, au d'autre part, vous faites:

non_pod_type* p = new non_pod_type();

vous obtenez un pointeur qui est toujours valide, parce que new a créé un objet.

même pour les types de gousses, il y a une différence significative entre les deux:

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

ce morceau de code imprimerait une valeur non spécifiée, parce que les objets POD créés par malloc ne sont pas initialisés.

Avec new , vous pouvez spécifier un constructeur de appel, et ainsi obtenir une valeur bien définie.

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

si vous le souhaitez vraiment, vous pouvez utiliser new pour obtenir des objets POD non initialisés. Voir cette autre réponse pour plus d'information à ce sujet.

une autre différence est le comportement en cas de défaillance. Quand il ne parvient pas à allouer la mémoire, malloc renvoie un pointeur nul, tandis que new lance une exception.

le premier exige vous devez tester chaque pointeur retourné avant de l'utiliser, tandis que le dernier pointeur produira toujours des pointeurs valides.

pour ces raisons, dans le code C++, vous devez utiliser new , et non malloc . Mais même alors, vous ne devez pas utiliser new "en plein", parce qu'il acquiert les ressources dont vous avez besoin pour libérer plus tard. Lorsque vous utilisez new vous devez passer immédiatement son résultat dans une classe de gestion des ressources:

std::unique_ptr<T> p = std::unique_ptr<T>(new T()); // this won't leak
8
répondu R. Martinho Fernandes 2017-05-23 11:55:03

il y a quelques choses que new fait que malloc ne fait pas:

  1. new construit l'objet en appelant le constructeur de cet objet
  2. new ne nécessite pas de saisie typographique de la mémoire allouée.
  3. Il ne nécessite pas une quantité de mémoire allouée, plutôt, il faut un certain nombre de les objets à construire.

Donc, si vous utilisez malloc , alors vous devez faire au-dessus des choses explicitement, ce qui n'est pas toujours pratique. De plus, new peut être surchargé mais malloc ne peut pas l'être.

6
répondu herohuyongtao 2014-01-15 14:45:51

si vous travaillez avec des données qui n'ont pas besoin de construction/destruction et qui nécessitent des réallocations (par exemple, un large éventail d'ints), alors je crois que malloc/free est un bon choix car il vous donne realloc, qui est beaucoup plus rapide que new-memcpy-delete (il est sur ma machine Linux, mais je suppose que cela peut dépendre de la plate-forme). Si vous travaillez avec des objets C++ qui ne sont pas POD et nécessitent construction/destruction, alors vous devez utiliser les opérateurs new et delete.

de toute façon, je ne vois pas pourquoi vous ne devriez pas utiliser les deux (à condition que vous libériez votre mémoire mallocée et supprimiez les objets alloués avec new) si vous pouvez profiter de l'augmentation de vitesse (parfois importante, si vous réallouez de grands tableaux de POD) que realloc peut vous donner.

sauf si vous en avez besoin, vous devriez vous en tenir à new/delete en C++.

4
répondu PSkocik 2013-04-09 12:35:17

si vous avez du code C que vous voulez transférer vers C++, vous pouvez laisser n'importe quel appel malloc() dedans. Pour tout nouveau code C++, je recommande d'utiliser new à la place.

3
répondu Fred Larson 2008-10-08 19:52:10

si vous utilisez C++ alors essayez d'utiliser new/delete à la place de malloc/calloc car ils sont l'opérateur son auto par rapport à malloc/calloc pour eux que vous avez utilisé pour inclure un autre en-tête pour cela.alors ne mélangez pas deux langues différentes en un seul codage.leur travail est similaire de toutes les façons les deux alloue la mémoire dynamiquement à partir du segment tas dans la table de hachage.

3
répondu user3488100 2014-04-02 09:13:02

D'un point de vue plus bas, new initialisera toute la mémoire avant de donner la mémoire tandis que malloc conservera le contenu original de la mémoire.

1
répondu Peiti Peter Li 2011-08-14 20:31:35

new initialise les valeurs par défaut de la structure et lie correctement les références qu'elle contient à elle-même.

E. G.

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

ainsi new struct test_s renverra une structure initialisée avec une référence de travail, tandis que la version malloc'ed n'a pas de valeurs par défaut et les références internes ne sont pas initialisées.

0
répondu lama12345 2016-12-14 15:46:27

les opérateurs new et delete peuvent opérer sur des classes et des structures, tandis que malloc et free ne fonctionnent qu'avec des blocs de mémoire à lancer.

L'utilisation de new/delete vous aidera à améliorer votre code car vous n'aurez pas besoin de lancer la mémoire allouée à la structure de données requise.

0
répondu selwyn 2017-06-11 10:30:57

Rare cas à considérer l'utilisation de malloc / free au lieu de new / delete est quand votre allocation et ensuite la réallocation (types de pod simples, pas d'objets) en utilisant realloc car il n'y a pas de fonction similaire à realloc en c++ (bien que cela puisse être fait en utilisant une approche plus c++)

0
répondu Florentino Tuason 2017-07-29 06:17:05

dans le scénario suivant, nous ne pouvons pas utiliser le nouveau puisqu'il appelle le constructeur.

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;
    }
};
-1
répondu Barry 2012-08-17 07:26:08

malloc () est utilisé pour assigner dynamiquement la mémoire en C alors que le même travail est fait par new() en C++. Ainsi, vous ne pouvez pas mélanger les conventions de codage de 2 langues. Il serait bon si vous avez demandé la différence entre calloc et malloc()

-4
répondu Hitesh Ahuja 2012-07-26 05:41:38