Référence cpp † déclare que :
Les objets avec des constructeurs par défaut triviaux peuvent être créés en utilisant la fonction
reinterpret_cast
sur n'importe quelle mémoire alignée de manière appropriée, par exemple sur une mémoire allouée avec l'optionstd::malloc
.
Cela implique que le code suivant est bien défini :
struct X { int x; };
alignas(X) char buffer[sizeof(X)]; // (A)
reinterpret_cast<X*>(buffer)->x = 42; // (B)
Trois questions suivent :
- Cette citation est-elle correcte ?
- Si oui, à quel moment la durée de vie de la
X
commencer ? Si en ligne(B)
Est-ce que c'est le plâtre lui-même qui est considéré comme un stockage d'acquisition ? Si c'est en ligne(A)
et s'il y avait une branche entre(A)
y(B)
qui construirait conditionnellement unX
ou une autre capsule,Y
? - Y a-t-il des changements entre C++11 et C++1z à cet égard ?
† Notez qu'il s'agit d'un ancien lien. Le libellé a été modifié en réponse à cette question. Il se lit maintenant comme suit :
Contrairement au C, cependant, les objets avec des constructeurs par défaut triviaux ne peuvent pas être créés en réinterprétant simplement un stockage correctement aligné, tel que la mémoire allouée avec
std::malloc
: placement-new est nécessaire pour introduire formellement un nouvel objet et éviter un comportement potentiel non défini.
0 votes
J'ai essayé de répondre à la question de savoir quand commence la vie de ces objets. Je n'ai pas été en mesure de trouver une réponse définitive dans la norme, et je crois qu'elle est vague à cet égard. Pour ce qui est de la première question, je doute que la citation soit correcte, car il faut faire attention à la règle d'aliasing.
0 votes
@SergeyA tant que le tampon est un tampon char, l'aliasing strict n'est pas un problème.
3 votes
Non, et je croyais qu'on avait déjà parlé de ça plusieurs fois ? [intro.object]/1 énumère de manière exhaustive les constructions du langage qui peuvent créer des objets.
4 votes
@RichardHodges, non.
char*
peut être un alias tout ce qui est mais tout ce qui est ne peut pas aliaserchar*
0 votes
@SergeyA si c'était vrai, il ne serait pas permis d'aliaser la mémoire d'une variante.
0 votes
@T.C. Pourriez-vous écrire une bonne réponse canonique à ce sujet ? Aide-moi, T.C., tu es mon seul espoir.
0 votes
@RichardHodges, je ne suis pas sûr de ce que vous voulez dire par variante dans ce contexte.
0 votes
@SergeyA
std::variant
oboost::variant
par exemple. Le stockage ne peut pas être alloué avec une union car il n'y a aucun moyen de construire une union à partir d'une liste de types. Vous utilisez donc un std::aligned_storage, qui est simplement un tampon char aligné qui est au moins aussi grand et aussi aligné que le type le plus restrictif de la liste de types.4 votes
@RichardHodges En fait, vous pouvez utiliser une union (récursive), et vous devez en utiliser une si vous le souhaitez.
constexpr
.0 votes
C'est parce qu'il vient d'être réparé. il y a quelques minutes
0 votes
@M.M. J'ai corrigé la formulation de la question.