2010-08-01 7 views
2

Étant donné un pointeur vide vers un "blob" de mémoire brute, il y a deux façons d'écrire quelque chose dessus.Ecriture de types hors classe dans la mémoire brute

La première méthode consiste à utiliser le placement nouveau. Cette méthode a l'avantage d'appeler le ctor automagiquement quand on a affaire à des classes-types. Cependant, quand je traite des types hors classe, serait-il préférable de faire un casting à la place? J'imagine que ça pourrait être plus rapide.

(pLocation est un pointeur nul dans une goutte de mémoire

// ----- Is this better ----- 
*reinterpret_cast<char*>(pLocation) = pattern; 

// ----- Or is this better ----- 
::new(pLocation) char(pattern); 
+0

Vous ne savez pas exactement ce que vous essayez d'obtenir ici, mais 'pattern' ne sera pas copié dans' pLocation' dans le 1er échantillon - vous pouvez simplement le remplacer par 'pLocation = pattern;' si vous cherchez juste pour l'attribution de pointeur. – adamk

+2

motif est un caractère. Il sera copié là où pLocation pointe vers, le code compile et fonctionne comme prévu. Les deux déclarations sont équivalentes dans ce cas. – aCuria

+1

Dans les deux cas, veillez à ce que pLocation soit correctement alignée avec les restrictions de limite de mots sur votre plate-forme. Par exemple, vous pourriez être en mesure de mettre un 'char' n'importe où, mais vous ne pourriez pas mettre un' long' n'importe où sauf les adresses qui sont multiples de sa taille. –

Répondre

3

J'ai eu un coup d'oeil à l'assemblée généré pour chacune de ces techniques, en utilisant le programme suivant:

#include <new> 

char blob[128]; 

int main() { 
    void *pLocation = blob; 
    char pattern = 'x'; 
#ifdef CAST 
    *reinterpret_cast<char*>(pLocation) = pattern; 
#else 
    ::new(pLocation) char(pattern); 
#endif 
} 

J'utilise g ++ 4.4.3 sur Linux 64 bits avec des drapeaux du compilateur par défaut.

La partie pertinente de l'asm pour placement new:

movb $120, -1(%rbp) 
    movq -16(%rbp), %rax 
    movq %rax, %rsi 
    movl $1, %edi 
    call _ZnwmPv 
    movq %rax, %rdx 
    testq %rdx, %rdx 
    je .L5 
    movzbl -1(%rbp), %edx 
    movb %dl, (%rax) 
.L5: 

D'après ce que je comprends, cela appelle en fait le placement nouvel opérateur, et vérifie sa valeur de retour, même si elle réussit toujours. Il continue ensuite d'écrire la valeur de x dans la mémoire retournée.

Et pour la reinterpret_cast:

movb $120, -1(%rbp) 
    movq -16(%rbp), %rax 
    movzbl -1(%rbp), %edx 
    movb %dl, (%rax) 

Notez que ces instructions sont identiques aux deux premiers et les deux derniers du placement la version new.

En utilisant -O1, les deux morceaux de code génèrent identiques Assemblée:

movb $120, blob(%rip) 

Donc, si vous êtes inquiet au sujet des performances, ne soyez pas. N'importe quel autre compilateur sain réduira probablement tous les deux le même code.

3

Bien que la coulée mémoire brute en objets pourrait fonctionner dans la pratique, il invoque officiellement un comportement non défini et à la suite de cela, conformément à la norme C++ , votre code peut faire quoi que ce soit.

placement nouveau, OTOH, est une technique d'invoquer un constructeur à une adresse particulière, et la construction est ce qui transforme officiellement la mémoire brute en objets valides. Voilà pourquoi je préférerais le placement nouveau.
Juste pour être sûr, j'aurais aussi le destructeur pour de tels objets est appelé. Bien que vous disiez que vous n'avez besoin que de POD et que la destruction des PODs est un non-op, beaucoup de bugs que j'ai vus dans mon transporteur étaient dans un code qui avait été écrit avec un ensemble de restrictions, mais plus tard certaines restrictions ont été levées et s'est soudainement trouvé dans un environnement avec lequel il était incapable de faire face.

Notez également qu'il peut exister des plates-formes pour lesquelles tous les modèles binaires possibles ne sont pas des valeurs valides, même pour un type intégré. De telles plates-formes pourraient également piéger l'accès aux valeurs d'un tel motif. Par exemple, il se peut qu'un modèle de bits à zéro tout entier ne soit pas une valeur valide pour un type flottant, de sorte que même la réduction à zéro de la mémoire à l'avance n'a pas pu empêcher une exception matérielle.

Questions connexes