una qué librería librerias libreria lenguaje dev descargar crear clases c++ memory-management c++14 allocation

qué - librerias dev c++ pdf



¿Cómo deberían las bibliotecas de C++ permitir asignadores personalizados? (1)

En C, es simple para una biblioteca permitir al usuario personalizar la asignación de memoria mediante el uso de punteros de función globales a una función que debería comportarse de manera similar a malloc() y a una función que debería comportarse de manera similar a free() . SQLite, por ejemplo, utiliza este enfoque.

C ++ complica un poco las cosas porque la asignación y la inicialización suelen estar fusionadas. Esencialmente queremos obtener el comportamiento de tener el operator new anulado operator new y el operator delete solo para una biblioteca, pero no hay manera de hacerlo (estoy bastante seguro, pero no del 100%).

¿Cómo debe hacerse esto en C ++?

Here una primera aproximación a algo que replica algunas de las semánticas de las new expresiones con una función Lib::make<T> .

No sé si esto es tan útil, pero solo por diversión, here una versión más complicada que también intenta replicar la semántica de las new[] expresiones new[] .

Esta es una pregunta orientada a objetivos, por lo que no necesariamente estoy buscando una revisión de código. Si hay una forma mejor de hacerlo, simplemente dígalo e ignore los enlaces.

(Por "asignador" solo me refiero a algo que asigna memoria. No me refiero al concepto de asignador STL o incluso asignando necesariamente memoria para contenedores).

Por qué esto podría ser deseable:

Here una publicación de blog de un desarrollador de Mozilla que sostiene que las bibliotecas deberían hacer esto. Da algunos ejemplos de bibliotecas de C que permiten al usuario de la biblioteca personalizar la asignación para la biblioteca. Revisé el código fuente de uno de los ejemplos, SQLite, y veo que esta función también se usa internamente para realizar pruebas a través de inyección de fallas. No estoy escribiendo nada que deba ser tan a prueba de balas como SQLite, pero aún parece una idea sensata. Si nada más, permite que el código del cliente descubra, "¿Qué biblioteca está acaparando mi memoria y cuándo?".


Respuesta simple: no uses C ++. Lo siento broma

Pero si desea tomar este tipo de control absoluto sobre la administración de la memoria en C ++, a través de las bibliotecas y los límites de los módulos, y de una manera completamente generalizada, puede sufrir un terrible dolor. Yo sugeriría a la mayoría buscar razones para no hacerlo más que formas de hacerlo.

He pasado por muchas iteraciones de esta misma idea básica a lo largo de los años (en realidad, décadas), desde tratar de sobrecargar ingenuamente al operador new / new [] / delete / delete [] a nivel global hasta soluciones basadas en enlazadores a plataformas específicas. Soluciones, y en realidad estoy en el punto deseado en el que se encuentra ahora: tengo un sistema que me permite ver la cantidad de memoria asignada por complemento. Pero no llegué a este punto a través de la forma generalizada en que lo deseas (y también yo, originalmente).

C ++ complica un poco las cosas porque la asignación y la inicialización suelen estar fusionadas.

Le daría un pequeño giro a esta afirmación: C ++ complica las cosas porque la inicialización y la asignación suelen estar fusionadas . Todo lo que hice fue intercambiar el pedido aquí, pero la parte más complicada no es que la asignación se quiera inicializar, sino porque la inicialización a menudo se quiere asignar.

Tomemos este ejemplo básico:

struct Foo { std::vector<Bar> stuff; };

En este caso, podemos asignar fácilmente Foo a través de un asignador de memoria personalizado:

void* mem = custom_malloc(sizeof(Foo)); Foo* foo = new(foo_mem) Foo; ... foo->~Foo(); custom_free(foo);

... y, por supuesto, podemos envolver todo lo que nos gusta para cumplir con RAII, lograr una seguridad excepcional, etc.

Excepto ahora el problema cae en cascada. Ese miembro del stuff usa std::vector querrá usar std::allocator , y ahora tenemos un segundo problema que resolver. Podríamos usar una creación de instancias de std::vector utilizando nuestro propio asignador, y si necesita que la información de tiempo de ejecución se pase al asignador, puede anular los constructores de Foo para pasar esa información junto con el asignador al constructor de vectores.

Pero ¿qué pasa con Bar ? Su constructor también puede querer asignar memoria para una variedad de objetos dispares, por lo que el problema cae en cascada y en cascada y en cascada.

Dada la dificultad de este problema, y ​​las soluciones alternativas y generalizadas que he probado y el dolor asociado al realizar el traslado, me he decidido por un enfoque completamente des-generalizado, algo pragmático.

La solución que decidí es reinventar con eficacia toda la biblioteca estándar de C y C ++. Asqueroso, lo sé, pero tenía un poco más de excusa para hacerlo en mi caso. El producto en el que estoy trabajando es, efectivamente, un motor y un kit de desarrollo de software, diseñado para permitir que las personas escriban complementos para él utilizando cualquier compilador, tiempo de ejecución de C, implementación de la biblioteca estándar de C ++ y configuraciones de compilación que deseen. Para permitir que cosas como vectores, conjuntos o mapas pasen a través de estas API centrales de una manera compatible con ABI, es necesario rodar nuestros propios contenedores que cumplen con las normas, además de una gran cantidad de funciones estándar de C.

Toda la implementación de este devkit gira en torno a estas funciones de asignación:

EP_API void* ep_malloc(int lib_id, int size); EP_API void ep_free(int lib_id, void* mem);

... y la totalidad del SDK gira en torno a estos dos, incluidos los grupos de memoria y los "subasignadores".

Para bibliotecas de terceros fuera de nuestro control, solo somos SOL. Algunas de esas bibliotecas tienen cosas igualmente ambiciosas que quieren hacer con el manejo de su memoria, y tratar de anularlas solo conducirían a todo tipo de choques y abrirían todo tipo de latas de gusanos. También hay controladores de muy bajo nivel cuando se utilizan elementos como OGL que quieren asignar una gran cantidad de memoria del sistema, y ​​no podemos hacer nada al respecto.

Sin embargo, he encontrado que esta solución funciona lo suficientemente bien como para responder a la pregunta básica: "¿quién / qué está acaparando toda esta memoria?" muy rápidamente: una pregunta que a menudo es mucho más difícil de responder que una similar relacionada con los ciclos de reloj (para la cual podemos activar cualquier perfilador). Solo se aplica al código que está bajo nuestro control, usando este SDK, pero podemos obtener un desglose de memoria muy completo usando este sistema por módulo. También podemos establecer límites superficiales en el uso de la memoria para asegurarnos de que los errores de falta de memoria en realidad se manejen correctamente sin intentar agotar todas las páginas contiguas disponibles en el sistema.

Entonces, en mi caso, este problema se resolvió mediante una política: mediante la creación de un estándar de codificación uniforme y una biblioteca central que se utiliza en todo el código base (y por parte de terceros que escriben complementos para nuestro sistema). Probablemente no sea la respuesta que está buscando, pero esta terminó siendo la solución más práctica que hemos encontrado hasta ahora.