sirve que para bzero c++ initialization memset

c++ - que - memset char c



¿Debería el programador C++ evitar el memset? (11)

Además de la maldad cuando se aplica a las clases, memset también es propenso a errores. Es muy fácil desordenar los argumentos, o olvidar el sizeof porción. El código generalmente se compilará con estos errores y silenciosamente hará lo incorrecto. El síntoma del error podría no manifestarse hasta mucho más tarde, lo que dificultaría el rastreo.

memset también es problemático con muchos tipos simples, como punteros y punto flotante. Algunos programadores establecen todos los bytes en 0, suponiendo que los punteros serán NULL y los flotantes serán 0.0. Esa no es una suposición portátil.

Escuché un dicho que los programadores de C ++ deben evitar memset,

class ArrInit { //! int a[1024] = { 0 }; int a[1024]; public: ArrInit() { memset(a, 0, 1024 * sizeof(int)); } };

entonces, teniendo en cuenta el código anterior, si no usas memset, ¿cómo podrías hacer que [1..1024] llene cero? ¿Qué pasa con memset en C ++?

Gracias.


El problema no es tanto usar memset () en los tipos incorporados, sino usarlos en tipos de clase (también conocidos como no POD). Si lo hace, casi siempre hará lo incorrecto y con frecuencia lo fatal: puede, por ejemplo, pisotear un puntero de tabla de funciones virtuales.


En C ++ std::fill o std::fill_n puede ser una mejor opción, ya que es genérico y, por lo tanto, puede operar tanto en objetos como en POD. Sin embargo, memset opera en una secuencia de bytes sin procesar y, por lo tanto, nunca debe usarse para inicializar no POD. Independientemente, las implementaciones optimizadas de std::fill pueden usar internamente especialización para llamar a memset si el tipo es un POD.


En C ++ debes usar nuevo. En el caso de matrices simples como en su ejemplo, no hay un problema real con su uso. Sin embargo, si tuviera una matriz de clases y usara memset para inicializarlo, no estaría construyendo las clases apropiadamente.

Considera esto:

class A { int i; A() : i(5) {} } int main() { A a[10]; memset (a, 0, 10 * sizeof (A)); }

No se invocará el constructor para cada uno de esos elementos, por lo que la variable miembro i no se establecerá en 5. Si utilizó new en su lugar:

A a = new A[10];

de que cada elemento en la matriz tendrá su constructor llamado y me estableceré en 5.


Es "malo" porque no estás implementando tu intento.

Su intención es establecer que cada valor en la matriz sea cero y lo que ha programado es establecer un área de memoria sin procesar a cero. Sí, las dos cosas tienen el mismo efecto, pero está más claro simplemente escribir código para poner a cero cada elemento.

Además, es probable que no sea más eficiente.

class ArrInit { public: ArrInit(); private: int a[1024]; }; ArrInit::ArrInit() { for(int i = 0; i < 1024; ++i) { a[i] = 0; } } int main() { ArrInit a; }

Al compilar esto con Visual C ++ 2008 32 bit con las optimizaciones activadas se compila el ciclo hacia -

; Line 12 xor eax, eax mov ecx, 1024 ; 00000400H mov edi, edx rep stosd

Que es más o menos exactamente lo que el memset probablemente compilaría de todos modos. Pero si usa memset no hay margen para que el compilador realice optimizaciones adicionales, mientras que al escribir su intento es posible que el compilador realice optimizaciones adicionales, por ejemplo, darse cuenta de que cada elemento se configura más tarde en otra cosa antes de que se use para que el compilador la inicialización puede optimizarse, lo que probablemente no podría hacer con la misma facilidad si hubiera usado memset.


Este es un hilo VIEJO, pero aquí hay un giro interesante:

class myclass { virtual void somefunc(); }; myclass onemyclass; memset(&onemyclass,0,sizeof(myclass));

funciona PERFECTAMENTE bien!

Sin embargo,

myclass *myptr; myptr=&onemyclass; memset(myptr,0,sizeof(myclass));

de hecho establece los virtuales (es decir, somefunc () arriba) en NULL.

Dado que memset es drásticamente más rápido que establecer 0 en todos y cada uno de los miembros de una clase grande, he estado haciendo el primer memset anterior durante años y nunca tuve un problema.

Entonces, la pregunta realmente interesante es ¿cómo es que funciona? Supongo que el compilador comienza a establecer el cero MÁS ALLÁ de la mesa virtual ... ¿Alguna idea?


La inicialización cero debería verse así:

class ArrInit { int a[1024]; public: ArrInit(): a() { } };

En cuanto al uso de memset, hay un par de maneras de hacer que el uso sea más robusto (como con todas esas funciones): evite codificar con fuerza el tamaño y el tipo de matriz:

memset(a, 0, sizeof(a));

Para comprobaciones adicionales en tiempo de compilación, también es posible asegurarse de que, de hecho, es una matriz (por lo que sizeof(a) tendría sentido):

template <class T, size_t N> size_t array_bytes(const T (&)[N]) //accepts only real arrays { return sizeof(T) * N; } ArrInit() { memset(a, 0, array_bytes(a)); }

Pero para los tipos sin carácter, me imagino que el único valor con el que lo llenarías es 0, y la inicialización cero ya debería estar disponible de una forma u otra.


La respuesta corta sería usar un std :: vector con un tamaño inicial de 1024.

std::vector< int > a( 1024 ); // Uses the types default constructor, "T()".

El valor inicial de todos los elementos de "a" sería 0, ya que el constructor std :: vector (size) (así como también el vector :: resize) copia el valor del constructor predeterminado para todos los elementos. Para tipos incorporados (también conocidos como tipos intrínsecos o POD), se garantiza que el valor inicial sea 0:

int x = int(); // x == 0

Esto permitiría que el tipo que "a" utiliza para cambiar con un alboroto mínimo, incluso a la de una clase.

La mayoría de las funciones que toman un puntero void (void *) como parámetro, como memset, no son de tipo seguro. Ignorar el tipo de un objeto, de esta manera, elimina todos los objetos semánticos de estilo C ++ en los que tienden a confiar, como la construcción, la destrucción y la copia. memset hace suposiciones sobre una clase, lo cual viola la abstracción (sin saber o preocuparse por lo que hay dentro de una clase). Si bien esta violación no siempre es inmediatamente obvia, especialmente con los tipos intrínsecos, puede conducir a errores difíciles de localizar, especialmente a medida que la base de código crece y cambia de dueño. Si el tipo que es memset es una clase con un vtable (funciones virtuales), también sobrescribirá esos datos.


Lo que está mal con memset en C ++ es casi lo mismo que con memset en C. memset llena la región de la memoria con un patrón físico de cero bits, mientras que en realidad en casi el 100% de los casos necesitas llenar una matriz con valores lógicos cero de tipo correspondiente. En lenguaje C, memset solo garantiza la inicialización correcta de la memoria para tipos enteros (y su validez para todos los tipos enteros, en oposición a solo tipos de caracteres, es una garantía relativamente reciente añadida a la especificación del lenguaje C). No se garantiza que ajuste correctamente a cero los valores de coma flotante, no se garantiza que produzca punteros nulos adecuados.

Por supuesto, lo anterior podría verse como excesivamente pedante, ya que los estándares y convenciones adicionales activos en la plataforma dada podrían (y ciertamente lo harán) extender la aplicabilidad de memset , pero aún así sugeriría seguir el principio de la navaja de Occam aquí: no Confíe en otros estándares y convenciones a menos que realmente deba hacerlo. El lenguaje C ++ (así como una C) ofrece varias funciones de nivel de idioma que le permiten inicializar de manera segura sus objetos agregados con los valores cero correctos de tipo correcto. Otras respuestas ya mencionan estas características.


No hay una razón real para no usarlo, excepto por los pocos casos que las personas señalaron que nadie usaría de todos modos, pero tampoco hay un beneficio real al usarlo, a menos que esté llenando dispositivos de memoria o algo.


Tu código está bien. Pensé que el único momento en C ++ donde memset es peligroso es cuando haces algo como:
YourClass instance; memset(&instance, 0, sizeof(YourClass); YourClass instance; memset(&instance, 0, sizeof(YourClass);

Creo que podría poner a cero los datos internos en su instancia que creó el compilador.