Renvoie la valeur du placement nouveau

Considérez le code C ++ 14 suivant:

#include  #include  #include  struct NonStandardLayout { // ... }; int main() { using T = NonStandardLayout; std::aligned_storage_t storage; T *const valid_ptr = new(static_cast(&storage)) T; T *const maybe_ptr = reinterpret_cast(&storage); assert(maybe_ptr == valid_ptr); // ??? valid_ptr->T::~T(); return 0; } 

Est-il garanti par la norme que l’assertion dans l’exemple ne faillira jamais, pour aucun type T?

Discussion

En regardant dans la dernière norme ( http://eel.is/c++draft/ ), je ne vois aucune référence à ce scénario particulier, mais j’ai trouvé les paragraphes suivants qui indiquent sans doute que la réponse est «oui».

Est-il correct de ma part de penser que [expr.new/15] et [new.delete.placement / 2] indiquent ensemble que la valeur de valid_ptr sera égale à l’adresse de storage , toujours?

Si tel est le cas, est-il vrai que la reinterpret_castreinterpret_cast générera un pointeur sur un object entièrement construit? Parce que, [expr.reinterpret.cast / 7], [expr.static.cast / 13] et [basic.compound / 4] semblent indiquer que ce devrait être le cas.

D’après mes observations, les implémentations de librairie de l’allocateur par défaut semblent ressembler à cela et sans souci! Est-il vraiment prudent de lancer comme ça?

Comment pouvons-nous être sûrs que les deux pointeurs seront les mêmes, ou pouvons-nous?

Je suis surpris que personne n’ait encore mentionné ce contre-exemple bon marché:

 struct foo { static foo f; // might seem dubious but doesn't violate anything void* operator new(size_t, void* p) {return &f;} }; 

Démo sur Coliru .

Cependant, à moins qu’une version d’emplacement spécifique à la classe ne soit appelée, votre assertion doit être vérifiée. Les deux expressions doivent représenter la même adresse que celle expliquée dans l’autre réponse (le point principal étant que l’ operator new standard non alloueur operator new renvoie simplement l’argument du pointeur et que la nouvelle expression ne fait rien d’extraordinaire), et aucune de ces expressions n’est un pointeur passé la fin de certains objects donc, par [expr.eq] / 2, ils se comparent égaux.

18.6.1.3 Formulaires de placement [new.delete.placement]

opérateur void * new (std :: size_t size, void * ptr) noexcept;

Retours: ptr.

Il est précisé sans ambiguïté que l’opérateur de placement new renvoie le pointeur qui lui est transmis. “Retours: ptr”. Je ne peux pas être plus clair que ça.

C’est à peu près cela qui scelle l’affaire pour moi en ce qui concerne “la valeur de retour de placement nouveau”: le placement new ne fait rien au pointeur qu’il place, et renvoie toujours le même pointeur.

Tout le rest de votre question concerne tout autre changement qui pourrait survenir à la suite des autres dissortingbutions. mais vous vous interrogez spécifiquement sur la valeur de retour de placement new , je suppose donc que vous acceptez le fait que toutes les autres conversions sont uniquement des conversions de type et n’ont aucun effet sur le pointeur réel, et que vous posez une question sur le placement new. – mais il serait également possible de passer en revue les autres castes et de prendre une décision similaire.