003
04.07.2010, 00:39 Uhr
0xdeadbeef
Gott (Operator)
|
Im konkreten Fall muss der string beim Aufruf von open (oder des Konstruktors) gültig sein. Danach wird er nicht mehr gebraucht. std::string::c_str() gibt einen Speicherbereich zurück, der der betreffenden Instanz von std::string gehört und um den diese sich zu kümmern hat; das heißt, dass der Speicherbereich ungültig wird, sobald die Instanz zerstört wird.
Zusätzlich kann er ungültig werden wie folgt:
Zitat von ISO/IEC 14882:2003 13.2 (5): |
References, pointers, and iterators referring to the elements of a basic_string sequence may be invalidated by the following uses of that basic_string object:
— As an argument to non-member functions swap() (21.3.7.8), operator>>() (21.3.7.9), and getline() (21.3.7.9). — As an argument to basic_string::swap(). — Calling data() and c_str() member functions. — Calling non-const member functions, except operator[](), at(), begin(), rbegin(), end(), and rend(). — Subsequent to any of the above uses except the forms of insert() and erase() which return iterators, the first call to non-const member functions operator[](), at(), begin(), rbegin(), end(), or rend().
|
Letzteres ist im Zusammenhang mit referenzzählenden Implementationen wichtig.
Beispiele:
C++: |
std::string s = "foo"; char const *p = s.c_str();
s.clear();
// p ist jetzt ungültig.
|
Das war ziemlich offensichtlich. Weniger offensichtlich (und wohl auch eher selten tatsächlich explosiv):
C++: |
std::string s = foo; char const *p = s.c_str(); char const *q = s.c_str();
// p ist jetzt ungültig.
|
Außerdem:
C++: |
std::string s = "foo";
char const *p = s.c_str(); s[0] = 'h';
// p jetzt ungültig.
|
Der Hintergrund hierfür ist, dass std::string nicht nullterminiert sein muss. (!) c_str() muss lediglich einen Speicherbereich organisieren, der dem Inhalt des Strings zum Aufrufszeitpunkt entspricht; dieser muss nicht mit dem ursprünglichen Datenbereich übereinstimmen (deswegen auch die Unterscheidung zwischen c_str() und data()). Der std::string darf in diesem Moment auch seinen Datenbereich umschichten und einen Sentinel anhängen, oder beispielsweise eine Sonderbehandlung für leere Strings machen, um etwa heap contention zu vermeiden. -- Einfachheit ist Voraussetzung für Zuverlässigkeit. -- Edsger Wybe Dijkstra Dieser Post wurde am 04.07.2010 um 00:47 Uhr von 0xdeadbeef editiert. |