2010-03-08 9 views
5

Consultez le code suivant:chaîne s; &s+1; Légal? UB?

#include <cstdlib> 
#include <iostream> 
#include <string> 
#include <vector> 
#include <algorithm> 
using namespace std; 

int main() 
{ 
    string myAry[] = 
    { 
     "Mary", 
     "had", 
     "a", 
     "Little", 
     "Lamb" 
    }; 
    const size_t numStrs = sizeof(myStr)/sizeof(myAry[0]); 

    vector<string> myVec(&myAry[0], &myAry[numStrs]); 

    copy(myVec.begin(), myVec.end(), ostream_iterator<string>(cout, " ")); 

    return 0; 
} 

d'intérêt est ici &myAry[numStrs]: numStrs est égal à 5, donc &myAry[numStrs] des points à quelque chose qui n'existe pas; le sixième élément dans le tableau. Il y a un autre exemple de ceci dans le code ci-dessus: myVec.end(), qui pointe à un-passé-le-fin du vecteur myVec. Il est parfaitement légal de prendre l'adresse de cet élément qui n'existe pas. Nous connaissons la taille de string, donc nous savons où l'adresse du 6ème élément d'un tableau de type C de string doit pointer. Tant que nous évaluons seulement ce pointeur et ne le déréférons jamais, nous allons bien. Nous pouvons même le comparer à d'autres indicateurs d'égalité. La STL le fait tout le temps dans des algorithmes qui agissent sur une gamme d'itérateurs. L'itérateur end() dépasse la fin et les boucles continuent à boucler pendant qu'un compteur != end().

Alors maintenant, considérez ceci:

#include <cstdlib> 
#include <iostream> 
#include <string> 
#include <vector> 
#include <algorithm> 
using namespace std; 

int main() 
{ 
    string myStr = "Mary"; 
    string* myPtr = &myStr; 
    vector<string> myVec2(myPtr, &myPtr[1]); 

    copy(myVec2.begin(), myVec2.end(), ostream_iterator<string>(cout, " ")); 

    return 0; 
} 

Est-ce code juridique et bien défini? Il est légal et bien défini de prendre l'adresse d'un élément de tableau après la fin, comme dans &myAry[numStrs], alors devrait-il être légal et bien défini de prétendre que myPtr est aussi un tableau?

Répondre

12

Il est légal et non UB d'avoir un pointeur vers "un après la fin" d'un tableau, et un seul objet peut être traité comme s'il était dans un tableau de longueur 1; Cependant, vous devez utiliser ptr + 1 à cause de la technicité de &ptr[1] déréférencement, puis en prenant l'adresse. Ceci s'applique également à &array[size] devenant array + size. Ce que vous avez fonctionnera comme vous l'avez prévu sur toutes les plateformes dont je suis au courant, mais étant donné qu'il est facile d'utiliser le formulaire sans ambiguïté, je ne vois aucune raison de ne pas le faire à la place.

+8

+1 pour plus de précision. Non seulement il est facile de le faire correctement, mais il évite aussi d'autres pièges avec l'opérateur & 'étant surchargé (il est mauvais de le surcharger, oui, mais cela montre comment il suffit de faire glisser les dépendances). Le mieux est de rester libre de tout comportement indéfini. –

5

La norme C de dans 5,6/4 « opérateurs additif » dit:

Aux fins de ces opérateurs, un pointeur vers un objet nonarray se comporte comme un pointeur vers le premier élément d'un tableau de longueur un avec le type de l'objet comme son type d'élément.

La norme C99 6.5.6/7 indique essentiellement la même chose.

Questions connexes