Considérer
int main()
{
auto a = new int[0];
delete[] a; // So there's no memory leak
}
Entre l'initialisation et la suppression de la copie, êtes-vous autorisé à lire le pointeur sur a + 1
?
En outre, la langue ne permet au compilateur de jeu a
à nullptr
?
c++
language-lawyer
Bathsheba
la source
la source
a
à coup sûr (vous ne pouvez certainement pas le déréférencer).a + 1
", le code suivant est-ilauto b = a + 1;
un comportement non défini? (Je pense que c'est).0
est en fait le résultat d'une expression que vous ne saurez pas avant l'exécution. Puisqu'ilnew int[0]
est sûr, il pourrait vous éviter de vous soucier de certains cas de branchement / spéciaux. Imaginez si je devais initialiser unstd::vector
avecstd::vector<int> v(0);
.Réponses:
Selon [basic.compound.3] , la valeur stockée dans
a
doit être l'une des suivantes:int
)Nous pouvons exclure la première possibilité car aucun objet de type n'a été
int
construit. La troisième possibilité est exclue car C ++ nécessite le retour d'un pointeur non nul (voir [basic.stc.dynamic.allocation.2] ). Il nous reste donc deux possibilités: un pointeur après la fin d'un objet ou un pointeur invalide.Je serais enclin à voir
a
comme un pointeur passé la fin, mais je n'ai pas de référence fiable pour établir définitivement cela. (Il y a, cependant, une forte implication de ceci dans [basic.stc] , voir comment vous pouvezdelete
ce pointeur.) Je vais donc envisager les deux possibilités dans cette réponse.Le comportement n'est pas défini, comme dicté par [expr.add.4] , quelle que soit la possibilité ci-dessus qui s'applique.
Si
a
est un pointeur passé la fin, alors il est considéré comme pointant vers l'élément hypothétique à l'index0
d'un tableau sans éléments. L'ajout de l'entierj
àa
n'est défini que lorsque0≤0+j≤n
, oùn
est la taille du tableau. Dans notre cas,n
est nul, donc la sommea+j
n'est définie que lorsquej
est0
. En particulier, l'ajout1
n'est pas défini.Si
a
est invalide, alors nous tombons proprement dans "Sinon, le comportement n'est pas défini". (Sans surprise, les cas définis ne couvrent que des valeurs de pointeur valides.)Non. D'après la [basic.stc.dynamic.allocation.2] mentionnée ci-dessus : "Si la demande aboutit, la valeur renvoyée par une fonction d'allocation remplaçable est une valeur de pointeur non nulle" . Il existe également une note de bas de page indiquant que C ++ (mais pas C) nécessite un pointeur non nul en réponse à une demande nulle.
la source
Selon une récente discussion sur le réflecteur CWG à la suite du numéro éditorial 3178 ,
new int[0]
produit ce qui est actuellement appelé une valeur de pointeur "après la fin" .Il s'ensuit que
a
cela ne peut pas être nul eta + 1
n'est pas défini par [expr.add] / 4 .la source
new int[0]
produit ce qui est actuellement appelé une valeur de pointeur" après la fin "" Ce n'est pas exact. Il n'y a pas eu beaucoup de discussions. Une personne a suggéré que la valeur soit "pointeur au-delà de la fin d'un objet", et cette déclaration a été remise en question car dans le cas d'un tableau avec des0
éléments, il n'y a aucun objet devant être passé la fin de.a + 1
n'est pas défini dans tous les cas, donc votre point ne concerne que sia
peut être nul?a + 1
n'est pas défini et peut-être que la valeur résultante du pointeur sera appelée "pointeur après la fin". Je ne dis pas que la réponse est fausse. Il est légèrement inexact, car on pourrait comprendre qu'il y a eu une longue discussion avec un consensus selon lequel il suffit de spécifier que le résultat est "pointeur après la fin" est suffisant pour résoudre le problème. Le problème avec "pointeur au-delà de la fin" est qu'il est au-delà de la fin d'un objet et soustraire1
d'une telle valeur de pointeur donne un pointeur à l'objet, ce qui ne devrait probablement pas être le cas pour les tableaux d'0
éléments.