Dans votre exemple, *(p1 + 1) = 10;
devrait être UB, parce que c'est un passé la fin de la matrice de taille 1. Mais nous sommes dans un cas très spécial ici, car le tableau a été construit dynamiquement dans un grand char tableau.
Dynamique de création de l'objet est décrit dans 4.5 Le C++ object model [intro.objet], §3 de la n4659 projet de la norme C++:
3 Si un objet est créé (8.3.4) dans le stockage associé à un autre objet e de type "tableau de N
unsigned char" ou de type "tableau de N std::byte" (21.2.1), ce tableau fournit un espace de stockage pour le créé
objet si:
(3.1) - la durée de vie de e a commencé et pas terminé, et
(3.2) - le stockage pour le nouvel objet s'adapte entièrement à l'intérieur de e, et
(3.3) - il n'y a pas de plus petit objet tableau qui répond à ces contraintes.
Le 3.3 semble pas claire, mais les exemples ci-dessous que l'intention soit plus clair:
struct A { unsigned char a[32]; };
struct B { unsigned char b[16]; };
A a;
B *b = new (a.a + 8) B; // a.a provides storage for *b
int *p = new (b->b + 4) int; // b->b provides storage for *p
// a.a does not provide storage for *p (directly),
// but *p is nested within a (see below)
Ainsi dans l'exemple, l' buffer
tableau fournit un espace de stockage pour les deux *p1
et *p2
.
Les paragraphes suivants prouver que l'objet, pour les deux *p1
et *p2
est buffer
:
4 un objet est imbriqué dans un autre objet b si:
(4.1) - a est un sous-objet de b, ou
(4.2) - b fournit un espace de stockage pour un, ou
(4.3) - il existe un objet de c, où a est imbriquée à l'intérieur de c, et c est imbriquée dans b.
5 Pour chaque objet x, il existe un certain objet appelé l'objet complet de x, déterminé comme suit:
(5.1) - Si x est un objet, alors l'objet de x est lui-même.
(5.2) - dans le cas Contraire, l'objet de x est l'objet de la (unique) de l'objet qui contient x.
Une fois que cela est établi, l'autre partie du projet de n4659 pour C++17 est [de base.coumpound] §3(souligner le mien):
3 ... Tous les
valeur de type pointeur est l'un des suivants:
(3.1) - un pointeur vers un objet ou une fonction (le pointeur est dit pour pointer vers l'objet ou la fonction), ou
(3.2) - un pointeur passé la fin d'un objet (8.7), ou
(3.3) - la valeur de pointeur null (7.11) pour ce type, ou
(3.4) - une valeur de pointeur non valide.
Une valeur de type pointeur est un pointeur vers le passé ou la fin d'un objet représente l'adresse de l'
le premier octet dans la mémoire (4.4) occupée par l'objet ou le premier octet dans la mémoire après la fin de la de stockage
occupée par l'objet, respectivement. [ Note: Un pointeur passé la fin d'un objet (8.7) n'est pas considéré comme
point de un sans rapport avec l'objet du type de l'objet qui pourrait être situé à cette adresse. Une valeur de type pointeur
devient non valide lors de l'entreposage, il dénote atteint la fin de sa durée de stockage; voir 6.7. -la note de fin ]
Pour les fins de l'arithmétique des pointeurs (8.7) et de comparaison (8.9, 8.10), un pointeur passé à la fin du dernier élément
d'un ensemble x de n éléments est considéré comme équivalent à un pointeur vers un hypothétique élément x[n]. L'
la valeur de la représentation de type pointeur est mise en œuvre définies. Les pointeurs de mise en page compatible avec types de
ont la même valeur de la représentation et de l'alignement des exigences (6.11)...
La note d'Un pointeur passé à la fin... ne s'applique pas ici, car les objets pointés par p1
et p2
et pas sans rapport, mais sont imbriqués dans le même objet, de sorte que le pointeur de l'arithmétique sens à l'intérieur de l'objet qui fournit une capacité de stockage: p2 - p1
est définie et est - (&buffer[sizeof(int)] - buffer]) / sizeof(int)
1.
Donc, p1 + 1
est un pointeur vers *p2
, et *(p1 + 1) = 10;
a défini le comportement et définit la valeur de *p2
.
J'ai aussi lu le C4 annexe sur la compatibilité entre le C++14 et courant (C++17) des normes. Suppression de la possibilité d'utiliser le pointeur de l'arithmétique entre les objets créés dynamiquement dans un seul tableau de caractères serait un changement important qui à mon humble avis devrait être citée, car elle est couramment utilisée pour la fonction. Que rien à ce sujet existent dans la compatibilité des pages, je pense qu'il confirme qu'il n'était pas l'intention de la norme pour l'interdire.
En particulier, il irait à l'encontre de cette dynamique commune de la construction d'un tableau d'objets à partir d'une classe sans constructeur par défaut:
class T {
...
public T(U initialization) {
...
}
};
...
unsigned char *mem = new unsigned char[N * sizeof(T)];
T * arr = reinterpret_cast<T*>(mem); // See the array as an array of N T
for (i=0; i<N; i++) {
U u(...);
new(arr + i) T(u);
}
arr
peut alors être utilisé comme un pointeur vers le premier élément d'un tableau...