40 votes

Est indice négatif pour l'opérateur [] - elles bien définies?

Je sais qu'il serait très mauvais codage de style, mais le code suivant fonctionne parfaitement sur ma machine. Mais c'est le comportement bien défini? Portable?

int main()
{
    int *p = new int[3];
    int *q = &p[2];
    q[-1] = 41;
    std::cout << p[1];
    delete[] p;
}

44voto

TartanLlama Points 1461

Ce qui est bien définie, à la fois syntaxiquement et sémantiquement.

[expr.sub]/1 (N3337):

L'expression E1[E2] est identique (par définition) à l' *((E1)+(E2)).

Donc, votre expression est la même que *(q-1) = 41;, donc est syntaxiquement valide.

[expr.ajouter]/5 (N3337)

Lorsqu'une expression qui a le type intégral est ajoutée ou déduite à partir d'un pointeur, le résultat est du type du pointeur de l'opérande. Si le pointeur de l'opérande points à un élément d'un objet de tableau, et le tableau est assez grand, le résultat des points à un élément de décalage de l'élément d'origine, tels que la différence des indices résultant de l'original et les éléments du tableau est égale à l'intégrale de l'expression.

Depuis q de points à un élément d'un tableau d'objets d'une taille valide pour votre expression intégrale, il est sémantiquement valide.

18voto

Benjamin Lindley Points 51005

Oui, elle est bien définie. Construit-en operator[] est définie en termes de l'arithmétique des pointeurs. Ce:

p[N]

p est un pointeur et d' N est un nombre entier, est équivalent à ceci:

*(p + N)

Un intéressant résultat de ceci est que c':

N[p]

est aussi équivalent, parce que l'addition est commutative.

7voto

Vlad from Moscow Points 36219

Selon la Norme C++ (5.2.1 Subscripting)

1 postfix expression suivie par une expression entre crochets est un postfix expression. L'une des expressions du type "tableau de T" ou "pointeur de T" et l'autre doit avoir délimité l'énumération ou de type intégral. Le résultat est de type "T". Le type "T" doit être complètement définie par type d'objet.65 L'expression E1[E2] est identique (par définition) à *((E1)+(E2)) ...

Donc vous pouvez utiliser n'importe quel type intégral, y compris le type int et, en conséquence, les valeurs négatives à condition que le résultat de l'expression *((E1)+(E2)) est bien formé.

Prendre en compte le fait que pour les types définis par l'utilisateur vous pouvez utiliser une orthèse-init-liste de l'index. Par exemple

#include <iostream>

class Point
{
public:    
    Point( int x, int y ) : x( x ), y( y ) {}
    int x, y;
};

class Circle
{
public:    
    Circle( unsigned int r ) : r( r ) {}

    Circle & operator []( Point p )
    {
        std::cout << "Drawing a circle at ( " << p.x << ", " << p.y << " )\n";
        return *this;
    }

    unsigned int r;
};        

int main()
{
    Circle circle( 10 );

    circle[ { 0, 0 } ];
}    

Le programme de la sortie est

Drawing a circle at ( 0, 0 )

3voto

L'index de l'opérateur x[idx] équivaut (*(x +idx)) et oui idx pourrait être négatif. Cependant, vous devez vous assurer que le pointeur déréférencé a été pointant vers une adresse mémoire valide.

Notez que nous pouvons réécrire à de nombreux égards (tout comme l'algèbre).

x[idx] = (*(x +idx)) = (*(idx + x)) = idx[x]

2voto

Paolo M Points 584

Il est parfaitement sûr et portable. Vous êtes simplement en utilisant l'arithmétique des pointeurs d'adresse de la mémoire allouée par l' new de l'opérateur.

Votre code est équivalent à:

int* p = new int[3];
int* q = p + 2;
*(q-1) = 41;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X