2016-11-11 2 views
-1

Ich konnte nicht verstehen, wie die Zeiger identisch sein können, wenn die Textgröße gleich ist. Es scheint so, als ob firstStringObj :: c_str() den Zeiger des vorherigen überschreibt. std :: string :: c_str() überschreibt die vorherige von einer Funktion zurückgegeben

#include <iostream> 
#include <string> 
#include <string> 
#include <stdio.h> 

std::string getConstCharAndModifyItWithANewString(const char* constchar) 
{ 
    std::string stringAtStack(constchar); 
    stringAtStack += "::isModified"; 
    return stringAtStack; 
} 

int main() 
{ 
    const char* firstConstCharPointer = getConstCharAndModifyItWithANewString("Hi!").c_str(); 
    std::string firstStringObj = "Hi+"; 

    printf(" firstConstCharPointer(%s)(%p)\nfirstStringObj(%s)(%p)\n\n", firstConstCharPointer,firstConstCharPointer, firstStringObj.c_str(),  firstStringObj.c_str() ); 
} 

OUTPUT: firstConstCharPointer (Hallo +) (0x4593eb8) firstStringObj (Hallo +) (0x4593eb8)

+0

wie ein Compiler Optimierungsproblem aussieht. Passiert nicht auf gcc 4.9.2 – ilo

+2

Sie beobachten undefiniertes Verhalten, so dass Sie Optimierungen nicht tadeln können. Außerdem: lies die Dokumentation von '.c_str()' – milleniumbug

+0

Nicht bei den langen Strings. – ilo

Antwort

1

Ihre Funktion gibt ein temporäresstd::string Objekt zurück. Nachdem die Variable firstConstCharPointer zugewiesen und der Ausdruck vollständig ist, wird das temporäre Objekt zerstört, wobei der zugewiesene Speicherblock freigegeben wird und die Variable auf den freigegebenen Speicher verweist. Dies ist bekannt als dangling Zeiger.

firstStringObj ordnet dann einen neuen Speicherblock, der passiert den gleichen Speicherblock zu sein, dass die Wiederverwendung Temp std::string zuvor zugewiesen war, und befreit. So passiert der baumelnde Zeiger , um wieder auf gültigen Speicher zu zeigen. Aus diesem Grund kann Ihre printf()-Anweisung dieselbe Speicheradresse und denselben Inhalt für beide Zeichenfolgen anzeigen.

Aber das ist undefined Verhalten.Der Speicherblock, der jedes Mal zugewiesen wird, ist vollständig auf die Allocator der Zeichenfolge zu entscheiden. Die zweite std::string könnte genauso leicht einen völlig anderen Speicherblock zugewiesen haben, und dann würde der Code eher abstürzen oder zumindest Unsinn ausgeben, wenn er versucht, den freien Zeiger, der immer noch auf ungültigen Speicher zeigt, zu dereferenzieren.

Damit Ihr Code zu arbeiten, müssen Sie firstConstCharPointer zu einem std::string Objekt ändern, so dass die Temperatur std::string richtig kopiert wird, zB:

#include <iostream> 
#include <string> 
#include <cstdio> 

std::string getConstCharAndModifyItWithANewString(const char* constchar) 
{ 
    std::string stringAtStack(constchar); 
    stringAtStack += "::isModified"; 
    return stringAtStack; 
} 

int main() 
{ 
    const std::string firstConstStringObj = getConstCharAndModifyItWithANewString("Hi!"); 
    std::string secondStringObj = "Hi!"; 

    std::printf(" firstConstStringObj(%s)(%p)\nsecondStringObj(%s)(%p)\n\n", firstConstStringObj.c_str(), firstConstStringObj.c_str(), secondStringObj.c_str(), secondStringObj.c_str()); 
} 
4

Die Zeiger sind gleich auf Ihrer Plattform, weil firstConstCharPointer ein baumelnden Zeiger ist, verweist er auf deallokierten Speicher.

Das ist, weil die std::string zurückgegeben vonnach Zuordnung Ausdruck const char* firstConstCharPointer = ...; zerstört wird.

Wenn Sie also ein neues Objekt std::string erstellen, wählen Sie für die Kompilierung den gleichen Speicherort wie das vorherige Objekt std::string, und die Zeiger sind daher identisch.

Auf meiner Plattform zum Beispiel die Zeiger sind die gleichen, und sie sind nicht in Ideone.

3

Sie haben klassisches undefiniertes Verhalten. printf versucht, firstConstCharPointer wegen %s zu demerefenrece. firstConstCharPointer Punkte auf Daten, die zerstört wurden, weil die std::string mit diesen Zeigern der Lebenszeit assoziiert stoppen nach der Zuweisung:

const char* firstConstCharPointer = getConstCharAndModifyItWithANewString("Hi!").c_str(); 
// temporary std::string returned from getConstCharAndModifyItWithANewString destroyed, pointer becomes dangling. 
3

Wie in documentation: angegeben

Der Zeiger von c_str erhalten() kann durch für ungültig erklärt werden:

  • eine nicht konstante Referenz auf die Zeichenfolge zu jeder Standard-Bibliotheksfunktion Passing oder
  • Aufrufen von nichtkonstanten Elementfunktionen in der Zeichenfolge, ausgenommen operator [], at(), front(), back(), begin(), rbegin(), end() und rend().

Sie sind also mit ungültiger Zeiger, als destructor eine nicht konstante Elementfunktion ist und nicht oben aufgeführt sind.

Verwandte Themen