2010-03-08 22 views
5

Considere el siguiente código:cuerdas s; &s+1; Legal? 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; 
} 

Resulta de interés &myAry[numStrs]: numStrs es igual a 5, por lo que &myAry[numStrs] apunta a algo que no existe; el sexto elemento en la matriz. Hay otro ejemplo de esto en el código anterior: myVec.end(), que apunta a un extremo del vector myVec. Es totalmente legal tomar la dirección de este elemento que no existe. Sabemos el tamaño de string, por lo que sabemos dónde debe apuntar la dirección del sexto elemento de una matriz C-style de string s. Siempre que solo evaluemos este puntero y nunca lo deslocalicemos, estamos bien. Incluso podemos compararlo con otros indicadores para la igualdad. El STL hace esto todo el tiempo en algoritmos que actúan sobre un rango de iteradores. El iterador end() apunta más allá del final, y los bucles siguen formando un contador != end().

Ahora considere esto:

#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; 
} 

Es este código legal y bien definida? Es legal y bien definido tomar la dirección de un elemento de matriz más allá del final, como en &myAry[numStrs], entonces ¿debería ser legal y bien definido pretender que myPtr también es una matriz?

Respuesta

12

Es legal y no UB tener un puntero a "uno más allá del final" de una matriz, y cualquier objeto individual puede tratarse como si estuviera en una matriz de longitud 1; sin embargo, necesita usar ptr + 1 en su lugar debido a la tecnicidad de &ptr[1] desreferencia y luego tomar la dirección. Esto también se aplica a &array[size] convirtiéndose en array + size.

Lo que tiene funcionará como espera en todas las plataformas de las que tengo conocimiento, pero teniendo en cuenta lo fácil que es usar la forma inequívocamente correcta, no veo ninguna razón para no hacer eso.

+8

+1 para precisión técnica. No solo es fácil hacer las cosas bien, sino que también se evitan otras trampas con 'operator &' sobrecargado (es malo sobrecargarlo, sí. Pero esto muestra cómo se arrastran las dependencias). Lo mejor es mantenerse libre de un comportamiento indefinido. –

5

estándar El C++ en 5,6/4 "operadores aditivos", dice:

Para los fines de estos operadores, un puntero a un objeto nonarray se comporta igual que un puntero al primer elemento de una matriz de longitud uno con el tipo del objeto como su tipo de elemento.

El C99 estándar 6.5.6/7 dice esencialmente lo mismo.