2010-03-08 13 views
5

Betrachten Sie den folgenden Code ein:Zeichenfolge 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; 
} 

Von Interesse ist hier &myAry[numStrs]: numStrs bis 5, so &myAry[numStrs] Punkte auf etwas gleich ist, das nicht existiert; das sechste Element im Array. Es gibt ein anderes Beispiel dafür in dem obigen Code: myVec.end(), der auf eins nach dem Ende des Vektors zeigt myVec. Es ist vollkommen legal, die Adresse dieses Elements zu nehmen, das nicht existiert. Wir kennen die Größe von string, also wissen wir, wo die Adresse des 6. Elements eines C-artigen Arrays von string s zeigen muss. Solange wir diesen Zeiger nur auswerten und ihn niemals dereferenzieren, geht es uns gut. Wir können es sogar mit anderen Hinweisen auf Gleichheit vergleichen. Die STL macht dies die ganze Zeit in Algorithmen, die auf eine Reihe von Iteratoren einwirken. Der end() Iterator zeigt nach dem Ende, und die Schleifen bleiben in Schleife, während ein Zähler != end().

Also das jetzt betrachten:

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

Ist dieser Code legal und gut definiert? Es ist legal und gut definiert, die Adresse eines Array-Elements nach dem Ende zu nehmen, wie in &myAry[numStrs], also sollte es legal und wohldefiniert sein, so zu tun, als wäre myPtr auch ein Array?

Antwort

12

Es ist legal und nicht UB, einen Zeiger auf "eins nach dem Ende" eines Arrays zu haben, und jedes einzelne Objekt kann so behandelt werden, als befände es sich in einem Array der Länge 1; Sie müssen jedoch stattdessen ptr + 1 verwenden, da die &ptr[1] Dereferenzierung und dann die Adressierung der Adresse. Dies gilt auch für wird array + size.

Was Sie haben, wird auf allen mir bekannten Plattformen funktionieren, aber angesichts der einfachen Verwendung des eindeutig korrekten Formulars sehe ich keinen Grund, dies nicht zu tun.

+8

+1 für technische Genauigkeit. Nicht nur, dass es einfach ist, es richtig zu machen, sondern es vermeidet auch weitere Fallstricke, bei denen "Operator &" überladen ist (es ist schlecht, es zu überlasten, ja. Aber das zeigt, wie man Abhängigkeiten nur schleppt). Am besten, sich von undefiniertem Verhalten frei zu halten. –

5

die Standard ++ C in 5,6/4 „Additive Operatoren“ sagt:

Für die Zwecke dieser Operatoren, ein Zeiger auf eine Nonarray Aufgabe eines Arrays das gleiche wie ein Zeiger auf das erste Element verhält Länge eins mit dem Typ des Objekts als Elementtyp.

Der C99-Standard 6.5.6/7 sagt im Wesentlichen das Gleiche.

Verwandte Themen