Pregunta

He visto una clase que es una clase que se define así ...

class StringChild : public StringBase
    {
public:
    //some non-virtual functions
    static StringChild* CreateMe(int size);
private:
    unsigned char iBuf[1];
    };

La función de fábrica estática tiene la siguiente implementación ...

return new(malloc(__builtin_offsetof(StringChild ,iBuf[size]))) StringChild();

Por lo que yo entiendo, esta función está utilizando la colocación nueva para extender esta clase.

¿Es esto seguro solo porque solo hay 1 miembro y está asignado en el montón?

¿Fue útil?

Solución

Es un viejo truco de C que se usaba para evitar la falta de disponibilidad de matrices de longitud variable en el plano C. Sí, también funciona en C ++ siempre que use construcciones de asignador adecuadas (como asignar un montón de memoria sin procesar tamaño deseado y luego colocación renovando el objeto allí). Es seguro siempre que no pase por el final de la memoria asignada, pero tiende a confundir al menos algunos depuradores de memoria.

Una cosa que debe asegurarse absolutamente al usar esta técnica es que la matriz de longitud variable es el último elemento en el diseño del objeto, de lo contrario, caminará sobre otras variables internas.

Sin embargo, estoy un poco dudoso acerca de la implementación de la función de fábrica: ¿supongo que el parámetro 'tamaño' es realmente el tamaño de matriz deseado? Además, no olvide que tendría que liberar la memoria anterior utilizando 'gratis' y no 'eliminar', aunque este último podría funcionar en la mayoría de los casos.

A menos que exista una razón convincente de por qué la memoria debe administrarse de esta manera, simplemente reemplazaría la matriz con std :: vector.

Otros consejos

Esto debería estar bien para los POD siempre que iBuf sea el último miembro de la estructura. Los problemas con los que no son POD podrían ser, por ejemplo. el compilador es libre de reordenar miembros públicos / privados / protegidos, las clases base virtuales terminan al final del objeto IIUC más derivado, etc.

Su estructura no es POD (tiene una clase base), por lo que no la recomendaría.

Además, si crea instancias como esta

return new(malloc(__builtin_offsetof(StringChild ,iBuf[size]))) StringChild();

Debes asegurarte de que la memoria adquirida por malloc se libere de forma gratuita, así que elimina tus instancias de esta manera:

obj->~StringChild();
free(obj);

Quizás desee utilizar :: operator new () para la asignación

Hablando estrictamente, dado que StringChild se deriva de StringBase no es seguro. El estándar C ++ no especifica el diseño de los subobjetos de la clase base. Cláusula 10, párrafo 3:

  

El orden en que se asignan los subobjetos de la clase base en el objeto más derivado (1.8) no está especificado.

Si StringChild fuera una estructura POD, entonces dicha técnica sería segura.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top