2010-03-08 20 views
5

Si consideri il seguente codice:string s; &s+1; Legale? 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; 
} 

Di interesse qui è &myAry[numStrs]: numStrs è uguale a 5, in modo da &myAry[numStrs] punti a qualcosa che non esiste; il sesto elemento nella matrice. C'è un altro esempio di questo nel codice di cui sopra: myVec.end(), che indica uno-oltre-la-fine del vettore myVec. È perfettamente legale prendere l'indirizzo di questo elemento che non esiste. Sappiamo le dimensioni di string, quindi sappiamo dove deve essere indirizzato l'indirizzo del sesto elemento di una matrice in stile C di string s. Finché valutiamo questo puntatore e non lo dereferiamo mai, stiamo bene. Possiamo persino confrontarlo con altri indicatori per l'uguaglianza. Lo STL lo fa sempre in algoritmi che agiscono su un intervallo di iteratori. L'iteratore end() punta oltre la fine e i loop continuano a scorrere mentre un contatore != end().

Così ora considerare questo:

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

È questo il codice legale e ben definito? È legale e ben definito prendere l'indirizzo di un elemento della matrice oltre la fine, come in &myAry[numStrs], quindi dovrebbe essere legale e ben definito fingere che myPtr sia anche un array?

risposta

12

È legale e non UB avere un puntatore a "uno dopo la fine" di un array e ogni singolo oggetto può essere trattato come se fosse in un array di lunghezza 1; tuttavia, è necessario utilizzare ptr + 1 invece a causa della tecnicità del dereferenziamento &ptr[1] e quindi prendere l'indirizzo. Questo vale anche per &array[size] diventando array + size.

Quello che hai funzionerà come ti aspetti su tutte le piattaforme di cui sono a conoscenza, ma dato quanto sia facile usare la forma inequivocabilmente corretta, non vedo motivo per non farlo invece.

+8

+1 per la precisione tecnica. Non solo è facile farlo correttamente, ma evita anche ulteriori insidie ​​con il fatto che l'operatore e 'sovraccarico (è brutto sovraccaricarlo, sì, ma questo mostra come si trascinino solo le dipendenze). Meglio restare senza comportamenti indefiniti. –

5

serie La C++ in 5,6/4 "operatori additivi" dice:

Ai fini di questi operatori, un puntatore ad un oggetto nonarray comporta come un puntatore al primo elemento di un array di lunghezza uno con il tipo dell'oggetto come tipo di elemento.

Lo standard C99 6.5.6/7 dice essenzialmente lo stesso.

Problemi correlati