c++ - privado - identificacion de skype
¿Es posible deshabilitar completamente el nuevo operador predeterminado de C++? (3)
Puede implementar el valor predeterminado new
para llamar a una función no implementada. Luego, en el momento del enlace, recibirá un error para los usuarios de la new
llamada:
#include <stdexcept>
inline void * operator new (std::size_t) throw(std::bad_alloc) {
extern void *bare_new_erroneously_called();
return bare_new_erroneously_called();
}
Cuando lo probé en IDEONE , obtuve este error:
/home/geXgjE/ccrEKfzG.o: In function `main'':
prog.cpp:(.text.startup+0xa): undefined reference to `bare_new_erroneously_called()''
collect2: error: ld returned 1 exit status
En mis pruebas, usando g++
, no hay error de enlace si no hay referencias al new
en el programa. Esto se debe a que g++
no emite código para funciones en inline
no utilizadas.
No tengo instalado Visual Studio en mi sistema, por lo que la siguiente información se basa en cierta documentación que he encontrado. Para poder ver el new
operador /FI detect_bare_new.h
en todas partes, debe poner su definición en un archivo de encabezado y luego usar la opción /FI detect_bare_new.h
en su compilador. * Según esta respuesta , Visual Studio no generará código para funciones en inline
no utilizadas (como g++
). Sin embargo, debe verificar si hay un nivel de optimización que deba habilitarse para ese comportamiento o no.
*
g++
tiene una opción de compilación similar:-include detect_bare_new.h
.
Esto supone que tiene la intención de pasar sus propios asignadores a las plantillas y clases de C ++ en la biblioteca estándar de C ++. Si no lo hace, el código insertado en los encabezados estándar que llaman al asignador predeterminado (que llamará new
) también activará el error de enlace. Si desea permitir que la biblioteca estándar de C ++ use la new
versión predeterminada, entonces una manera fácil de hacerlo funcionar (a expensas de tiempos de compilación más largos) es agregar todos los encabezados estándar de C ++ que pretenda incluir en la parte superior de la detect_bare_new.h
archivo.
Usted declara que la portabilidad de la solución no es importante para usted. Pero, para completar, debería resaltar el problema que Ben Voigt señala correctamente: El estándar C ++ no garantiza el comportamiento de no generar código para las funciones en inline
no utilizadas. Por lo tanto, uno puede obtener un error de enlace, incluso si la función no se utiliza. Pero, si el código no tiene otras referencias a la función no implementada excepto dentro de la new
implementación trozada, el error estaría dentro de la new
definición misma. Por ejemplo, g++
podría generar un error como:
/home/QixX3R/cczri4AW.o: In function `operator new(unsigned int)'':
prog.cpp:(.text+0x1): undefined reference to `bare_new_erroneously_called()''
collect2: error: ld returned 1 exit status
Si su sistema es uno que genera código para funciones en inline
no utilizadas, aún puede tener una solución alternativa. La solución funcionará si el vinculador informará todas las referencias erróneas a la función no definida. En ese caso, si el único error de vinculación observado se debe a la definición del new
operador, no hay llamadas inesperadas al new
. Después de verificar que el código solo tiene ese único error, puede cambiar la línea de enlace para incluir un objeto o biblioteca que tenga una definición adecuada de bare_new_erroneously_called()
que bare_new_erroneously_called()
una excepción de tiempo de ejecución.
Debido a que nuestra aplicación tiene un rendimiento duro y restricciones de memoria, nuestros estándares de codificación prohíben el uso del montón predeterminado, es decir, no malloc
, ni predeterminado new
. Cada asignación de memoria tiene que elegir uno de los pocos asignadores específicos; algo como
// declared globally
void* operator new( size_t size, CustomAllocHeap* heap, const char* perpetrator_name )
{
return heap->Allocate( size, perpetrator_name );
}
// imagine a bunch of CustomAllocHeap''s declared globally or statically, thus
Vector* v = new( gPhysicsHeap, __FUNCTION__ ) Vector( 1.0f, 2.0f, 3.0f, 4.0f );
// or in a class
Thingy* p = new( this->LocalArenaHeap, __FUNCTION__ ) Thingy();
Aunque hemos mantenido una buena disciplina en esto con nuestro código, algunos componentes estándar de C ++ (contenedores, std::function
) realizan llamadas de forma encubierta al new
montón predeterminado, lo cual es muy malo.
Sería bueno inhabilitar por completo el new
valor predeterminado, de modo que cualquier línea de código que implícitamente da como resultado una asignación predeterminada arroje inmediatamente un error de compilación. Eso nos permitiría notar estas cosas de inmediato.
Obviamente podemos hacer que new
throw sea un error de tiempo de ejecución, es decir,
void* operator new ( size_t ) { __debugbreak(); return NULL; }
pero sería mucho mejor recibir advertencias sobre esto en tiempo de compilación. ¿Es eso posible?
Nuestra aplicación está diseñada para una plataforma fija (x64 con Visual Studio); la portabilidad es irrelevante.
Si su propio "nuevo" operador no se llama "nuevo" sino de manera diferente (por ejemplo, "miNuevo"), podría usar un "#define" en lugar de "nuevo" por basura:
#define new *+-/&
El precompilador ahora reemplazaría a un "nuevo":
x = new mytype;
Por la basura:
x = *+-/& mytype;
La ventaja en comparación con un mensaje en tiempo de enlace es que esto generará un mensaje de compilación inmediatamente al compilar el archivo C ++, no al final al enlazar. También verá la línea donde se encuentra el "nuevo".
La desventaja es que tendrá que "#incluir" el archivo que contiene este "#define" en todos los archivos C ++ de su proyecto.
¡Veneno!
Si está utilizando GCC, hay un pragma para esto:
#ifdef __GNUC__
/* poision memory functions */
# pragma GCC poison malloc new
#endif