Quel est le but de std::blanchir?
P0137 introduit le modèle de fonction std::launder
et rend de nombreuses, de nombreuses modifications à la norme dans les sections concernant les syndicats, la durée de vie, et des pointeurs.
Quel est le problème de ce papier est de résoudre? Quelles sont les modifications à la langue que j'ai à être au courant? Et que sommes-nous launder
ing?
- Êtes-vous poser des questions sur le document lui-même ou sur
std::launder
?std::launder
est utilisé pour "obtenir un pointeur vers un objet créé dans le stockage occupé par un objet de même type, même si elle a const ou de référence des membres." - utile lien sur le sujet. Aussi cette question stackoverflow.com/questions/27003727/...
- Cela a maintenant été publié dans VC2017 dans la version 15.7.0
- Selon les mst, les pointeurs sont triviales types afin de blanchir de ne pas faire n'importe quoi. 😉
Vous devez vous connecter pour publier un commentaire.
std::launder
porte bien son nom, mais seulement si vous savez ce que c'est. Il effectue mémoire de blanchiment d'.Prenons l'exemple dans le document:
Cette instruction effectue globale de l'initialisation, l'initialisation de la première membre de
U
avec{1}
.Parce que
n
est unconst
variable, le compilateur est libre de supposer queu.x.n
est toujours 1.Donc ce qui se produit si nous le faisons:
Parce que
X
est trivial, nous n'avons pas besoin de détruire l'ancien objet avant d'en créer un nouveau à sa place, donc c'est parfaitement légal de code. Le nouvel objet aura san
membre de l'être 2.Alors dis-moi... ce sera
u.x.n
retour?La réponse la plus évidente sera de 2. Mais c'est faux, parce que le compilateur est permis de supposer que, vraiment
const
variable (pas simplement unconst&
, mais une variable d'objet déclaréconst
) ne changera jamais. Mais nous avons juste changé la.[de base.la vie]/8 énonce les circonstances dans lesquelles il est OK pour accéder à l'objet nouvellement créé par des variables/pointeurs/références à l'ancien. Et avoir un
const
membre est l'un des facteurs de disqualification.Donc... comment peut-on parler de
u.x.n
correctement?Nous avons à blanchir de notre mémoire:
Le blanchiment d'argent est utilisé pour empêcher les gens de traçage de l'endroit où vous avez obtenu votre argent. Mémoire de blanchiment d'argent est utilisé pour prévenir la compilateur de traçage de l'endroit où vous avez obtenu votre objet, ainsi forcer pour éviter toute optimisations qui peuvent ne plus s'appliquer.
Un autre de la disqualification de facteurs est que si vous changez le type de l'objet.
std::launder
peut aider à ici aussi:[de base.la vie]/8 nous dit que, si vous alloue un nouvel objet dans le stockage de l'ancien, vous ne pouvez pas accéder à la nouvelle de l'objet par le biais de pointeurs à l'ancienne.
launder
nous permet de côté-étape.std::launder<int *>(&data)
(où le paramètre formel est un pointeur void)?n
est unconst
variable, le compilateur est libre de supposer queu.x.n
doit toujours être 1." Où dans la norme, il n'est dit que? Je demande parce que le problème, vous l'avez souligné veut dire pour moi que c'est faux dans la première place. Il ne doit être vrai dans le cas de la règle, qui ne parvient pas ici. Ce qui me manque?&u.x
est un pointeur sur int const. Pourquoi est-il permis d'utiliser un pointeur const données dans un placement de nouveau?X
, pas unconst int
. Et vous devez autoriser cette option si vous souhaitez que le placement de nouveaux travaux sur les structures avecconst
membres, qui en général, vous ne voulez. Mêmeconst int
sorte de sens. Pensez personnalisé allocateurs de vastes quantités de petites, de taille égale, les objets qui les placer tous dans un bloc de mémoire alloué à cette fin.template <class T, class U> T* alias_cast(U* ptr) { return std::launder(reinterpret_cast<T*>(ptr)); }
Comment UB est qui?ptr
représente, alors vous cassezlaunder
s'condition, donc il n'y a pas de point de parler du résultat.const
-membre qualifié est toujours accessible ou pas. Le fait que le membre existe est suffisant pour l'obligerlaunder
sur l'ensemble du type contenant.memcpy
dans une réinterprétation sur la prise en charge (c'est à dire le laxisme de l'alignement) des plates-formes de toute façon.int* totallyNewPtr = new (&data) int;
, il n'y aurait pas besoin de laver quoi que ce soit parcetotallyNewPtr
est un nouveau pointeur vers l'objet qui n'a pas besoin d'être consulté par n'importe quel expiré objets?launder
est une fonction de la bibliothèque. Que faut-il réellement faire?u.x.n
ne peut pas être utilisé pour accéder à l'objet nouvellement créé, à cause de la cité de la règle. À l'aide delaunder
vous permet d'accéder à cet objet.launder
fournit un pointeur vers l'objet en direct en mémoire, puis il fournit un pointeur vers l'objet en direct en mémoire.launder
à l'égard de la génération de code, c'est que vous avez bien défini comportement dans certaines circonstances. Ce comportement est généré par le compilateur; il voit que vous avez effectué un mémoire de blanchiment d'argent et par conséquent, elle ne peut plus assumer les choses qu'il serait en mesure de les assumer. C'est, lorsque l'optimiseur va à travers et en tournant votreu.x.n
utilise dans le littéral1
, il frappelaunder
et va "Oups, ne peut pas voir à travers cette" et s'arrête.n
est const,x
n'est pas const. Le placement de nouveaux modifie l'objetu.x
, donc le compilateur ne doit pas supposer qu'une partie deu.x
a la même valeur qu'avant. Pas de blanchiment ne devrait être nécessaire.new
ne pas modifier l'objet; elle se termine l'ancien objet et en crée une nouvelle à sa place. Les Variables en C++ nom de objets; si vous le placement-new
sur un objet, alors la variable n'est pas nom plus. C++ permet d'indiquer le nom de l'ancien objet de reporter la nouvelle sous certaines circonstances. Mais en dehors de ces circonstances, le nom fait référence à l'ancien objet. Ce que vous voulez est un système où les noms ne sont pas des objets de nom, et par conséquent, toutconst
déclarées nom ne pouvait pas être interprétée comme une référence à un nom de la mêmeconst
objet. Donc, ce seraitconst
faire réellement?u.x
renvoie a été modifié ou remplacé. Donc tout ce qui se rapporte à cette par la suite ne devrait pas supposer qu'il n'a pas été modifié. Encore une fois, pas de blanchiment d'argent nécessaire. De demander au programmeur de mettre ce genre de chose explicitement est stupide.new
est à l'intérieur d'un conditionnel déclaration, de sorte que le compilateur ne peut pas savoir au moment de la compilation de la branche qui s'est passé. Demander à un compilateur de savoir à propos de choses qu'il ne peut pas connaître est stupide.u
et d'y accéder, de même si vous passez une référence àu
en tant que paramètre, le compilateur ne peut certainement optimiseru.x.n
. Pourquoi? Parce queconst
objets pas être modifiée, et par conséquent, le code qui le fait a suscité UB. Donc, pour en revenir à la valeur originale est valide "undefined" de comportement. Ce que vous me demandez, c'est juste pour en faire non pas défini en vertu de certains mal de circonstances particulières. Pourquoi s'embêter? Pourquoi ne pas simplement le respect que le nom d'unconst
objet se réfère toujours à l'origineconst
objet?u
ouu.x
comme une mutable pointeur ou une référence à une opaque fonction, le compilateur absolument a supposer queu.x.n
peut avoir été modifié par la fonction. Il peut jamais présumer le contraire. Si vous passeru
ouu.x
comme const pointeur ou de référence, alors oui, on peut supposer qu'il n'a pas changé-mais tout bien définis programme ne devrait pas changer de toute façon. Ainsi, il n'y a toujours pas d'exigence explicite de blanchiment d'annotations.const
, le code serait très bien, mais avec elle, vous devezlaunder
pour obtenir un pointeur vers l'objet. Alors qu'avec juste quelques initialisée de stockage, vous seriez toujours besoin delaunder
pour obtenir le pointeur à partir de l'adresse de l'espace de stockage.