¿En qué casos uso malloc vs new?

Veo que en C ++ hay múltiples formas de asignar y liberar datos, y entiendo que cuando llame a malloc debe llamar free y cuando use el new operador debe emparejar con delete y es un error mezclar los dos (por ejemplo, llamar free() en algo que se creó con el new operador), pero no tengo claro cuándo debo usar malloc / free y cuándo debería usar new / delete en mis progtwigs del mundo real.

Si usted es un experto en C ++, infórmeme sobre las reglas generales o convenciones que sigue a este respecto.

A menos que esté obligado a usar C, nunca debería usar malloc . Siempre usa new .

Si necesita una gran cantidad de datos simplemente haga algo como:

 char *pBuffer = new char[1024]; 

Tenga cuidado, aunque esto no es correcto:

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

En su lugar, debe hacer esto al eliminar una matriz de datos:

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

La new palabra clave es la forma C ++ de hacerlo, y asegurará que su tipo tendrá su constructor llamado . La new palabra clave también es más segura, mientras que malloc no es segura en absoluto.

La única forma en que podría pensar que sería beneficioso usar malloc sería si necesitara cambiar el tamaño de su buffer de datos. La new palabra clave no tiene una forma análoga como realloc . La función realloc podría ampliar el tamaño de una porción de memoria de manera más eficiente.

Vale la pena mencionar que no se puede mezclar new / free y malloc / delete .

Nota: Algunas respuestas en esta pregunta no son válidas.

 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 respuesta corta es: no use malloc para C ++ sin una buena razón para hacerlo. malloc tiene una serie de deficiencias cuando se usa con C ++, que se definió como new para superar.

Deficiencias corregidas por nuevo para el código C ++

  1. malloc no es seguro de ninguna manera significativa. En C ++, debes emitir el retorno desde el void* . Esto potencialmente presenta muchos problemas:

     #include  struct foo { double d[5]; }; int main() { foo *f1 = malloc(1); // error, no cast foo *f2 = static_cast(malloc(sizeof(foo))); foo *f3 = static_cast(malloc(1)); // No error, bad } 
  2. Aunque es peor que eso. Si el tipo en cuestión es POD (datos antiguos) , puede utilizar semi-sensiblemente malloc para asignarle memoria, como lo hace f2 en el primer ejemplo.

    Aunque no es tan obvio si un tipo es POD. El hecho de que sea posible que un tipo determinado cambie de POD a no POD sin errores de comstackción resultantes y potencialmente muy difícil de solucionar problemas es un factor importante. Por ejemplo, si alguien (posiblemente otro progtwigdor, durante el mantenimiento, mucho más tarde hiciera un cambio que provocara que foo dejara de ser POD, entonces no aparecería un error obvio en tiempo de comstackción como esperaría, por ejemplo:

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

    haría que el malloc de f2 también se volviera malo, sin ningún diagnóstico obvio. El ejemplo aquí es trivial, pero es posible introducir accidentalmente no PODness mucho más lejos (por ejemplo, en una clase base, agregando un miembro que no sea POD). Si tiene C ++ 11 / boost puede usar is_pod para comprobar que esta suposición es correcta y producir un error si no es así:

     #include  #include  foo *safe_foo_malloc() { static_assert(std::is_pod::value, "foo must be POD"); return static_cast(malloc(sizeof(foo))); } 

    Aunque boost no puede determinar si un tipo es POD sin C ++ 11 o algunas otras extensiones del comstackdor.

  3. malloc devuelve NULL si falla la asignación. new lanzará std::bad_alloc . El comportamiento de usar un puntero NULL posteriormente no está definido. Una excepción tiene una semántica limpia cuando se lanza y se lanza desde el origen del error. Envolver malloc con una prueba adecuada en cada llamada parece tedioso y propenso a errores. (Solo debes olvidar una vez para deshacer todo ese buen trabajo). Se puede permitir que una excepción se propague a un nivel en el que la persona que llama pueda procesarla con sensatez, mientras que NULL es mucho más difícil de transmitir de manera significativa. Podríamos extender nuestra función safe_foo_malloc para lanzar una excepción o salir del progtwig o llamar a algún controlador:

     #include  #include  void my_malloc_failed_handler(); foo *safe_foo_malloc() { static_assert(std::is_pod::value, "foo must be POD"); foo *mem = static_cast(malloc(sizeof(foo))); if (!mem) { my_malloc_failed_handler(); // or throw ... } return mem; } 
  4. Fundamentalmente malloc es una característica C y la new es una función C ++. Como resultado malloc no funciona bien con los constructores, solo busca asignar un trozo de bytes. Podríamos ampliar nuestro safe_foo_malloc para usar la ubicación new :

     #include  #include  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. Nuestra función safe_foo_malloc no es muy genérica; lo ideal sería que quisiéramos algo que pueda manejar cualquier tipo, no solo foo . Podemos lograr esto con plantillas y plantillas variadas para constructores no predeterminados:

     #include  #include  #include  void my_malloc_failed_handler(); template  struct alloc { template  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)...); } }; 

    Ahora, aunque hemos solucionado todos los problemas que hemos identificado hasta ahora, prácticamente hemos reinventado el new operador predeterminado. Si va a utilizar malloc y la ubicación new entonces también podría usar new para empezar.

Desde el C ++ FQA Lite :

[16.4] ¿Por qué debería usar un viejo malloc nuevo (en lugar de confiable)?

Preguntas frecuentes: nueva / eliminar llamar al constructor / destructor; nuevo es tipo seguro, malloc no; nuevo puede ser anulado por una clase.

FQA: Las virtudes de los nuevos mencionados por las preguntas frecuentes no son virtudes, porque los constructores, los destructores y la sobrecarga de operadores son basura (¿qué pasa cuando no tienes recolección de basura?), Y el problema de seguridad es muy pequeño aquí (normalmente tienes para emitir el vacío * devuelto por malloc al tipo de puntero derecho para asignarlo a una variable de puntero tipeada, que puede ser molesto, pero está lejos de ser “inseguro”).

Ah, y el uso de malloc antiguo confiable hace posible usar el realloc igual de confiable y antiguo. Es una lástima que no tengamos un nuevo y shiny operador para renovar o algo así.

Aún así, lo nuevo no es lo suficientemente malo como para justificar una desviación del estilo común utilizado en un idioma, incluso cuando el lenguaje es C ++. En particular, las clases con constructores no triviales se portarán de manera fatal si simplemente malloc los objetos. Entonces, ¿por qué no usar nuevo en todo el código? La gente rara vez sobrecarga al operador nuevo, por lo que probablemente no se interponga demasiado. Y si sobrecargan a los nuevos, siempre puede pedirles que se detengan.

Lo siento, simplemente no pude resistirme. 🙂

Siempre use nuevo en C ++. Si necesita un bloque de memoria sin tipo, puede usar el operador new directamente:

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

Utilice malloc y free solo para asignar memoria que va a administrar las bibliotecas y API centradas en c. Use new y delete (y las variantes [] ) para todo lo que controle.

nuevo vs malloc ()

1) new es un operador , mientras que malloc() es una función .

2) constructores de llamadas new , mientras que malloc() no lo hace.

3) new devuelve tipo de datos exacto , mientras que malloc() devuelve void * .

4) new nunca devuelve un NULL (arrojará en la falla) mientras que malloc() devuelve NULL

5) Reasignación de memoria no manejada por new mientras que malloc() puede

Hay una gran diferencia entre malloc y new . malloc asigna memoria. Esto está bien para C, porque en C, un trozo de memoria es un objeto.

En C ++, si no se trata de tipos POD (que son similares a los tipos C), debe llamar a un constructor en una ubicación de memoria para que realmente tenga un objeto allí. Los tipos que no son POD son muy comunes en C ++, ya que muchas características de C ++ hacen que un objeto no sea automáticamente POD.

new asigna memoria y crea un objeto en esa ubicación de memoria. Para los tipos que no son POD esto significa llamar a un constructor.

Si haces algo como esto:

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

El puntero que obtenga no se puede desreferenciar porque no apunta a un objeto. Necesitarás llamar a un constructor antes de que puedas usarlo (y esto se hace usando la ubicación new ).

Si, por otro lado, lo haces:

 non_pod_type* p = new non_pod_type(); 

Obtiene un puntero que siempre es válido, porque el new creó un objeto.

Incluso para los tipos de POD, hay una diferencia significativa entre los dos:

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

Este fragmento de código imprimirá un valor no especificado, porque los objetos POD creados por malloc no se inicializan.

Con el new , podría especificar un constructor para llamar, y así obtener un valor bien definido.

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

Si realmente lo quiere, puede usar use new para obtener objetos POD no inicializados. Vea esta otra respuesta para más información sobre eso.

Otra diferencia es el comportamiento ante el fracaso. Cuando no puede asignar memoria, malloc devuelve un puntero nulo, mientras que new arroja una excepción.

El primero requiere que pruebe cada puntero devuelto antes de usarlo, mientras que el último siempre generará punteros válidos.

Por estos motivos, en el código C ++ debe usar new y no malloc . Pero incluso entonces, no debe usar el new “al air libre”, ya que adquiere los recursos que necesita para lanzar más tarde. Cuando utiliza new , debe pasar su resultado de inmediato a una clase de gestión de recursos:

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

Para responder a su pregunta, debe saber la diferencia entre malloc y new . La diferencia es simple:

malloc asigna memoria , mientras que new asigna memoria Y llama al constructor del objeto para el que está asignando memoria.

Entonces, a menos que esté restringido a C, nunca debería usar malloc, especialmente cuando se trata de objetos de C ++. Esa sería una receta para romper tu progtwig.

También la diferencia entre free y delete es bastante similar. La diferencia es que delete llamará al destructor de su objeto además de liberar memoria.

Hay algunas cosas new que no hace malloc :

  1. new construye el objeto llamando al constructor de ese objeto
  2. new no requiere encasillado de memoria asignada.
  3. No requiere una cantidad de memoria para ser asignada, sino que requiere una cantidad de objetos para ser construida.

Entonces, si usa malloc , entonces debe hacer las cosas anteriores explícitamente, lo que no siempre es práctico. Además, los new pueden estar sobrecargados, pero malloc no puede ser.

Si trabajas con datos que no necesitan construcción / destrucción y requieren reasignaciones (por ejemplo, una gran variedad de ints), entonces creo que malloc / free es una buena opción, ya que te da realloc, que es mucho más rápido que new-memcpy -delete (está en mi caja de Linux, pero supongo que esto puede depender de la plataforma). Si trabaja con objetos C ++ que no son POD y requieren construcción / destrucción, entonces debe usar los operadores nuevos y eliminar.

De todos modos, no veo por qué no deberías usar ambos (siempre que liberes tu memoria mal definida y elimines los objetos asignados con nuevos) si puedes aprovechar el aumento de velocidad (a veces uno significativo, si estás realojando matrices grandes) de POD) que realloc puede darte.

A menos que lo necesite, debe seguir con new / delete en C ++.

Si está utilizando c ++, intente utilizar new / delete en lugar de malloc / calloc, ya que son operadores independientes comparados con malloc / calloc. Para ellos solía incluir otro encabezado. No mezcle dos idiomas diferentes en una sola encoding. .su trabajo es similar en cada forma, ambos asignan la memoria dinámicamente del segmento de montón en la tabla hash.

Si tiene un código C que desea transferir a C ++, puede dejar cualquier llamada malloc () en él. Para cualquier código C ++ nuevo, recomendaría usar nuevo en su lugar.

Desde una perspectiva más baja, nuevo inicializará toda la memoria antes de dar la memoria mientras que malloc mantendrá el contenido original de la memoria.

new inicializará los valores predeterminados de la estructura y vinculará correctamente las referencias a ella.

P.ej

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

Por lo tanto, las new struct test_s devolverán una estructura inicializada con una referencia de trabajo, mientras que la versión malloc’ed no tendrá valores predeterminados y las referencias internas no se inicializarán.

Los operadores new y de delete pueden operar en clases y estructuras, mientras que malloc y free solo funcionan con bloques de memoria que necesitan ser moldeados.

El uso de new/delete ayudará a mejorar su código, ya que no necesitará enviar la memoria asignada a la estructura de datos requerida.

Caso poco común para considerar utilizar malloc / free en lugar de new / delete es cuando se asignan y luego se reasignan (tipos de pod simples, no objetos) utilizando realloc ya que no existe una función similar a realloc en c ++ (aunque esto se puede hacer utilizando un c ++ enfoque)

En el siguiente escenario, no podemos usar new ya que llama al constructor.

 class B { private: B *ptr; int x; public: B(int n) { cout< <"B: ctr"<x = n + 10; } ~B() { //delete ptr; free(ptr); cout< <"B: dtr"< 

malloc () se usa para asignar dinámicamente la memoria en C mientras que el mismo trabajo se realiza con new () en c ++. Por lo tanto, no puede mezclar convenciones de encoding de 2 idiomas. Sería bueno si solicitara la diferencia entre calloc y malloc ()