Malloc vs nuevo-relleno diferente


Estoy revisando el código C++ de otra persona para nuestro proyecto que usa MPI para computación de alto rendimiento (10^5-10^6 núcleos). El código está destinado a permitir las comunicaciones entre (potencialmente) diferentes máquinas en diferentes arquitecturas. Ha escrito un comentario que dice algo como:

Normalmente usaríamos new y delete, pero aquí estoy usando malloc y free. Esto es necesario porque algunos compiladores rellenarán los datos de manera diferente cuando se usa new , que conduce a errores en la transferencia de datos entre diferentes plataformas. Esto no sucede con malloc.

Esto no encaja con nada que sepa de las preguntas estándar new vs malloc.

¿Cuál es la diferencia entre new / delete y malloc/free? sugiere la idea de que el compilador podría calcular el tamaño de un objeto de manera diferente (pero entonces, ¿por qué difiere de usar sizeof?).

Malloc & colocación nuevo vs. nuevo es un bastante popular pregunta pero solo habla de new usando constructores donde malloc no lo hace, lo cual no es relevante para esto.

¿Cómo entiende malloc la alineación? dice que se garantiza que la memoria esté correctamente alineada con new o malloc que es lo que había pensado anteriormente.

Mi conjetura es que ha diagnosticado mal su propio error algún tiempo en el pasado y dedujo que new y malloc dan diferentes cantidades de relleno, lo que creo que probablemente no es cierto. Pero no puedo encontrar el responde con Google o en cualquier pregunta previa.

Ayúdame, StackOverflow, ¡eres mi única esperanza!

Author: Community, 2012-11-08

8 answers

IIRC hay un punto delicado. malloc está garantizado para devolver una dirección alineada para cualquier tipo estándar. ::operator new(n) solo está garantizado para devolver una dirección alineada para cualquier tipo estándar no mayor que n, y si T no es un tipo de carácter, entonces new T[n] solo se requiere para devolver una dirección alineada para T.

Pero esto solo es relevante cuando estás jugando trucos específicos de la implementación, como usar los pocos bits inferiores de un puntero para almacenar banderas, o confiar en el dirección para tener más alineación de la que estrictamente necesita.

No afecta al relleno dentro del objeto, que necesariamente tiene exactamente el mismo diseño, independientemente de cómo haya asignado la memoria que ocupa. Por lo tanto, es difícil ver cómo la diferencia podría resultar en errores en la transferencia de datos.

¿Hay alguna señal de lo que piensa el autor de ese comentario sobre los objetos en la pila o en los globales, ya sea que en su opinión estén "acolchados como malloc" o "acolchados como nuevos"? Que podría dar pistas de dónde vino la idea.

Tal vez está confundido, pero tal vez el código del que está hablando es más que una diferencia directa entre malloc(sizeof(Foo) * n) vs new Foo[n]. Tal vez sea más como:

malloc((sizeof(int) + sizeof(char)) * n);

Vs.

struct Foo { int a; char b; }
new Foo[n];

Es decir, tal vez esté diciendo "Uso malloc", pero significa "Empaco manualmente los datos en ubicaciones no alineadas en lugar de usar una estructura". En realidad malloc no es necesario para empaquetar manualmente la estructura, pero no darse cuenta de que es una menor grado de confusión. Es necesario definir el diseño de los datos enviados a través del cable. Diferentes implementaciones rellenarán los datos de manera diferente cuando se use la estructura .

 25
Author: Steve Jessop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-08 11:49:58

Su colega puede haber tenido la galleta mágica de new[]/delete[] en mente (esta es la información que la implementación usa al eliminar un array). Sin embargo, esto no habría sido un problema si se hubiera utilizado la asignación que comienza en la dirección devuelta por new[] (a diferencia de la del asignador).

Empaquetar parece más probable. Las variaciones en ABI podrían (por ejemplo) dar lugar a un número diferente de bytes finales añadidos al final de una estructura (esto está influenciado por la alineación, también considere matriz). Con malloc, la posición de una estructura podría ser especificada y por lo tanto más fácilmente portátil a un ABI extranjero. Estas variaciones se evitan normalmente especificando la alineación y el embalaje de las estructuras de transferencia.

 5
Author: justin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-08 11:58:36

La disposición de un objeto no puede depender de si fue asignado usando malloc o new. Ambos devuelven el mismo tipo de puntero, y cuando pasa este puntero a otras funciones no sabrán cómo se asignó el objeto. sizeof *ptr solo depende de la declaración de ptr, no de cómo se asignó.

 3
Author: Barmar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-08 10:44:08

Creo que tienes razón. El relleno es hecho por el compilador no new o malloc. Las consideraciones de relleno se aplicarían incluso si declarara una matriz o estructura sin usar new o malloc en absoluto. En cualquier caso, aunque puedo ver cómo diferentes implementaciones de new y malloc podrían causar problemas al portar código entre plataformas, no veo por completo cómo podrían causar problemas al transferir datos entre plataformas.

 3
Author: john,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-30 07:41:51

Cuando quiero controlar el diseño de mi antigua estructura de datos, con compiladores MS Visual uso #pragma pack(1). Supongo que esta directiva precompiladora es compatible con la mayoría de los compiladores, como por ejemplo gcc.

Esto tiene la consecuencia de alinear todos los campos de las estructuras uno detrás del otro, sin espacios vacíos.

Si la plataforma en el otro extremo hace lo mismo (es decir, compiló su estructura de intercambio de datos con un relleno de 1), entonces los datos recuperados en ambos lados justs encaja bien. Por lo tanto, nunca he tenido que jugar con malloc en C++.

En el peor de los casos, habría considerado sobrecargar el nuevo operador para que realice algunas cosas complicadas, en lugar de usar malloc directamente en C++.

 0
Author: Stephane Rolland,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-30 09:02:36

Esta es mi conjetura salvaje de dónde viene esta cosa. Como usted mencionó, el problema es con la transmisión de datos a través de MPI.

Personalmente, para mis complicadas estructuras de datos que quiero enviar/recibir a través de MPI, siempre implemento métodos de serialización/deserialización que empaquetan/desempaquetan todo en/desde una matriz de caracteres. Ahora, debido al relleno sabemos que ese tamaño de la estructura podría ser mayor que el tamaño de sus miembros y por lo tanto también se necesita calcular el sin relleno tamaño de la estructura de datos para que sepamos cuántos bytes se envían / reciben.

Por ejemplo, si desea enviar/recibir std::vector<Foo> A sobre MPI con dicha técnica, es incorrecto asumir que el tamaño de la matriz de caracteres resultante es A.size()*sizeof(Foo) en general. En otras palabras, cada clase que implementa métodos serialize / deserialize, también debe implementar un método que informe el tamaño de la matriz (o mejor aún, almacenar la matriz en un contenedor). Esto podría convertirse en la razón detrás de un error. De una manera u otra, sin embargo, eso no tiene nada que ver con new vs malloc como se señala en este hilo.

 0
Author: GradGuy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-30 09:02:46

En c++: newla palabra clave se usa para asignar algunos bytes particulares de memoria con respecto a alguna estructura de datos. Por ejemplo, ha definido alguna clase o estructura y desea asignar memoria para su objeto.

myclass *my = new myclass();

O

int *i = new int(2);

Pero en todos los casos necesita el tipo de datos definido (class, struct, union, int, char, etc...) y solo se asignarán los bytes de memoria necesarios para su objeto/variable. (ie; múltiplos de ese tipo de datos).

Pero en caso del método malloc (), puede asignar cualquier byte de memoria y no necesita especificar el tipo de datos en todo momento. Aquí se puede observar en pocas posibilidades de malloc ():

void *v = malloc(23);

O

void *x = malloc(sizeof(int) * 23);

O

char *c = (char*)malloc(sizeof(char)*35);
 0
Author: Rahul Raina,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-14 08:11:08

Malloc es un tipo de función y nuevo es un tipo de tipo de datos en c++ en c++, si usamos malloc de lo que debemos y debemos usar typecast de lo contrario el compilador le dará error y si utilizamos nuevo tipo de datos para la asignación de memoria que no hay necesidad de encasillar

 -1
Author: hk_043,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-23 12:28:20