40 votes

Est-il possible de désactiver complètement le nouvel opérateur C ++ par défaut?

Parce que notre application est dur de performance et les contraintes de mémoire, nos normes de codage interdire l'utilisation de l'segment par défaut — c'est à dire, pas de malloc, aucun défaut new. Chaque allocation de mémoire doit choisir un des quelques allocateurs; quelque chose comme

// 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();

Même si nous avons maintenu une bonne discipline, avec notre code, une norme composants C++ (conteneurs, std::function ) secrètement de faire des appels à la valeur par défaut new tas, ce qui est très mauvais.

Il serait bien de le désactiver par défaut new au total, d'une certaine façon, de sorte que toute ligne de code qui, implicitement, les résultats en une allocation par défaut jette tout de suite une erreur de compilation. Qui nous auraient permis de remarquer ces choses tout de suite.

On peut évidemment faire new jeter une erreur d'exécution ie

void* operator new ( size_t ) { __debugbreak(); return NULL; }  

mais il serait beaucoup mieux pour obtenir des avertissements au sujet de cette au moment de la compilation. Est-ce possible?

Notre application est conçue pour une plate-forme fixe (x64 avec Visual Studio), la portabilité n'est pas pertinent.

18voto

jxh Points 32720

Vous pouvez mettre en œuvre la valeur par défaut new de faire appel à une fonction non implémentée. Puis, au moment de la liaison, vous obtiendrez un message d'erreur pour les utilisateurs de la nue - new appel:

#include <stdexcept>
inline void * operator new (std::size_t) throw(std::bad_alloc) {
    extern void *bare_new_erroneously_called();
    return bare_new_erroneously_called();
}

Quand je l'ai testé sur IDEONE, j'ai eu cette erreur:

/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

Dans mes tests, à l'aide de g++, il n'y a pas de lien d'erreur si il n'y a pas de références à la nue - new dans le programme. C'est parce qu' g++ n'émettent pas de code inutilisé inline fonctions.

Je n'ai pas de Visual Studio est installé sur mon système, de sorte que les informations suivantes sont basées sur la documentation que j'ai trouvé. Afin d'obtenir le inline new de l'opérateur pour être vus partout, vous devriez mettre à sa définition dans un fichier d'en-tête, puis utilisez l' /FI detect_bare_new.h option dans votre compilateur.* Selon cette réponse, Visual Studio génère pas de code inutilisé inline fonctions (comme g++). Toutefois, vous devriez vérifier pour voir si il y a un niveau d'optimisation qui doit être activé pour que le comportement ou pas.

* g++ a la même option de compilateur: -include detect_bare_new.h.

Cela suppose que vous avez l'intention de transmettre votre propre allocateurs pour les modèles C++ et des classes dans la bibliothèque C++ standard. Si vous ne le faites pas, alors inline code dans la norme en-têtes d'appel par défaut de l'allocateur (qui appellera new) déclenche l'erreur de couplage ainsi. Si vous souhaitez permettre à la bibliothèque C++ standard pour utiliser la valeur par défaut new, puis un moyen facile de le faire fonctionner (à la charge de l'allongement des temps de compilation) consiste à ajouter le standard C++ en-têtes que vous avez l'intention d'inclure dans le haut de l' detect_bare_new.h le fichier.

Vous dites que la portabilité de la solution n'est pas important pour vous. Mais par souci d'exhaustivité, je doit mettre en évidence le problème que Ben Voigt souligne à juste titre: La norme C++ ne garantit pas le comportement de ne pas générer de code inutilisé inline fonctions. Ainsi, on peut obtenir une erreur de couplage, même si la fonction n'est pas utilisée. Mais, si le code n'a pas d'autres références à la fonction non implémentée à l'exception de l'intérieur de l'écrasa new mise en œuvre, l'erreur doit être à l'intérieur de l' new définition elle-même. Par exemple, g++ pourrait générer une erreur de ce type:

/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 votre système est celui qui génère le code pour inutilisés inline fonctions, vous pouvez toujours avoir une solution de contournement. La solution de contournement ne fonctionne pas si l'éditeur de liens du rapport, toutes les références erronées à la fonction non définie. Dans ce cas, si la seule erreur de couplage observé est dû à la définition de l' new de l'opérateur lui-même, il n'y a pas inattendu appels à la nue - new. Après avoir vérifié que le code a la moindre erreur, vous pouvez alors changer le lien pour inclure un objet ou d'une bibliothèque qui a une définition appropriée de l' bare_new_erroneously_called() qui permettrait de lancer une exception d'exécution.

1voto

Martin Rosenau Points 2145

Si votre propre opérateur "new" n'est pas nommé "nouveau", mais différemment (par exemple, "monnouvel"), vous pouvez utiliser un "#define" en remplacement de "nouveau" par des ordures:

#define new *+-/&

Le pré-compilateur aurait désormais remplacer un "nouveau":

x = new mytype;

Par la les ordures:

x = *+-/& mytype;

L'avantage par rapport à un message au temps de lien, c'est que cela va générer un compilateur message immédiatement lors de la compilation du fichier C++, pas en fin de compte lors de la liaison. Vous voyez aussi la ligne où la "nouvelle" est situé.

L'inconvénient est que vous aurez à "#include" le fichier contenant cette "#define" dans tous les fichiers C++ dans votre projet.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X