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.
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
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++
-
malloc
n'est pas typesafe de façon significative. En C++, vous devez lancer le retour devoid*
. 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 }
-
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, commef2
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
def2
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 utiliseris_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.
-
malloc
retourneNULL
si la répartition échoue.new
lancerastd::bad_alloc
. Le comportement de l'utilisation ultérieure d'un pointeurNULL
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. Enveloppermalloc
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ù commeNULL
est beaucoup plus difficile à transmettre de façon significative. Nous pourrions étendre notre fonctionsafe_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; }
-
fondamentalement
malloc
est une caractéristique C etnew
est une caractéristique C++. En conséquencemalloc
ne joue pas très bien avec les constructeurs, il ne s'agit que d'allouer un morceau d'octets. Nous pourrions étendre notresafe_foo_malloc
plus d'utiliser le placementnew
:#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(); }
-
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 seulementfoo
. 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 utilisezmalloc
et de placementnew
, alors vous pourriez aussi bien utilisernew
pour commencer!
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. :)
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);
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.
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
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.
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
il y a quelques choses que new
fait que malloc
ne fait pas:
-
new
construit l'objet en appelant le constructeur de cet objet -
new
ne nécessite pas de saisie typographique de la mémoire allouée. - 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.
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++.
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.
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.
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.
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.
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.
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++)
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;
}
};
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()