L'emplacement par défaut new
opérateur est déclaré dans 18,6 [support.dynamique] ¶1 avec un non-lancer spécification d'exception:
void* operator new (std::size_t size, void* ptr) noexcept;
Cette fonction ne fait rien, sauf return ptr;
il est donc raisonnable pour qu'il soit noexcept
, cependant, selon 5.3.4 [expr.nouveau] ¶15 cela signifie que le compilateur doit vérifier qu'il ne retourne pas null avant d'appeler le constructeur de l'objet:
-15-
[Note: à moins d'une allocation de fonction est déclarée avec un non-lancer spécification d'exception (15.4), il indique un échec d'allocation de stockage en jetant unstd::bad_alloc
d'exception (article 15, 18.6.2.1); elle renvoie un pointeur non null sinon. Si la fonction d'allocation est déclarée avec un non-lancer spécification d'exception, elle renvoie la valeur null pour indiquer l'échec d'allocation de stockage et un pointeur non null sinon. -fin de la remarque] Si l'attribution de la fonction renvoie la valeur null, l'initialisation ne doit pas être fait, la fonction de libération ne doit pas être appelé, et la nouvelle valeur de l'expression est nulle.
Il me semble que (spécifiquement pour le placement new
, pas en général) cette null check est un malheureux performance de hit, mais modeste.
J'ai été le débogage de code où le placement new
a été utilisé dans une performance très sensible chemin de code pour améliorer le compilateur de la génération de code et de les vérifier pour les nuls a été observée dans l'assemblée. En fournissant une classe spécifique de placement new
de surcharge qui est déclarée avec un lancement spécification d'exception (même si elle ne peut pas les jeter) la branche conditionnelle a été supprimé, ce qui a également permis au compilateur de générer plus petit code pour les environs inline fonctions. Le résultat de dire le placement new
fonction pourrait lancer, même si elle ne pouvait pas, a été sensiblement meilleur code.
Donc je me demandais si la valeur null est à vérifier est vraiment nécessaire pour le placement new
des cas. La seule façon pour elle de retourner la valeur null est si vous passer la valeur null. Bien qu'il soit possible, et apparemment juridique, d'écrire:
void* ptr = nullptr;
Obj* obj = new (ptr) Obj();
assert( obj == nullptr );
Je ne vois pas pourquoi ce serait utile, je suggère qu'il serait mieux si le programmeur avait pour vérifier la valeur null explicitement avant d'utiliser le placement new
par exemple
Obj* obj = ptr ? new (ptr) Obj() : nullptr;
Quelqu'un a besoin de placement new
afin de gérer correctement le pointeur null cas? (c'est à dire sans ajout d'une vérification explicite qu' ptr
est valide emplacement de la mémoire.)
Je me demandais s'il serait raisonnable d'interdire le passage d'un pointeur null à l'emplacement par défaut new
de la fonction, et si pas de savoir si il ya une meilleure façon d'éviter l'inutile branche, d'autres que d'essayer de dire au compilateur que cette valeur n'est pas null par exemple
void* ptr = getAddress();
(void) *(Obj*)ptr; // inform the optimiser that dereferencing pointer is valid
Obj* obj = new (ptr) Obj();
Ou:
void* ptr = getAddress();
if (!ptr)
__builtin_unreachable(); // same, but not portable
Obj* obj = new (ptr) Obj();
N. B. Cette question est volontairement tagged micro-optimisation, je suis pas ce qui suggère que vous allez autour de la surcharge de placement new
pour tous vos types "d'améliorer" les performances. Cet effet a été remarqué dans un très spécifique de la performance-cas critique et basé sur le profilage et la mesure.