2012-07-06 11 views
6

Ich lerne immer noch C++, also bitte bitte mit mir. Ich schreibe einen einfachen Wrapper um Boost-Dateisystempfade - ich habe seltsame Probleme mit der Rückgabe von temporären Strings. Hier ist meine einfache Klasse (dies ist nicht genau, aber ziemlich nah dran):Temporäre Std :: Strings zurückkehrenden Müll

typedef const char* CString; 
typedef std::string String; 
typedef boost::filesystem::path Path; 

class FileReference { 

    public: 

     FileReference(const char* path) : mPath(path) {}; 

     // returns a path 
     String path() const { 
      return mPath.string(); 
     }; 

     // returns a path a c string 
     CString c_str() const { 
      return mPath.string().c_str(); 
     }; 

    private: 

     Path mPath; 

} 

Mit dem kleinen Testcode unter:

FileReference file("c:\\test.txt"); 

OutputDebugString(file.path().c_str()); // returns correctly c:\test.txt 
OutputDebugString(file.c_str());  // returns junk (ie îþîþîþîþîþîþîþîþîþîþî.....) 

Ich bin mir ziemlich sicher, dass dies mit Provisorien zu tun hat, aber ich kann nicht herausfinden, warum das wäre - sollte nicht alles korrekt kopiert werden?

+0

was ist die Quelle für 'Output()'? –

+2

krümmte sich bei 'typedef''ing Ihre eigene' CString' ... – Blindy

+1

@OttoAllmendinger - Es ist ein [Windows-API] (http://msdn.microsoft.com/en-us/library/windows/desktop/aa363362 (v = VS.85) ASPX-) -Funktion. –

Antwort

4

Sieht aus wie mPath.string() gibt eine Zeichenfolge nach Wert zurück. Dieses temporäre Zeichenfolgenobjekt wird zerstört, sobald FileReference :: c_str() zurückgibt, so dass c_str() ungültig wird. Mit einem solchen Modell ist es nicht möglich, eine c_str()-Funktion zu erstellen, ohne irgendeine Art von Klassen- oder Static-Level-Variablen für die Zeichenfolge einzuführen.

Betrachten Sie die folgenden Alternativen:

//Returns a string by value (not a pointer!) 
//Don't call it c_str() - that'd be misleading 
String str() const 
{    
    return mPath.string(); 
} 

oder

void str(String &s) const 
{    
    s = mPath.string(); 
} 
+0

Eine gültige Verwendung für den ersten Vorschlag wäre 'OutputDebugString (file.str(). c_str()); ' –

8
CString c_str() const { 
     return mPath.string().c_str(); 
    }; 

mPath.string() eine Kopie eines std::string zurückgibt. Diese Kopie wird in einem temporären gespeichert, der am Ende dieses Ausdrucks zerstört wird.

.c_str() gibt einen Zeiger auf Speicher zurück, der zerstört wird, wenn die Zeichenfolge zerstört wird, d. H. Am Ende dieses Ausdrucks.

Sie geben einen Zeiger auf den Speicher zurück, der bereits zerstört wurde.

+1

wenn er einen Zeiger will, könnte er zurückgeben m_path.c_str() – PermanentGuest

+0

@PermanentGuest - bist du sicher? Ich finde '.c_str()' nicht im Boost.Filesystem [Dokumentation] (http://www.boost.org/doc/libs/1_41_0/libs/filesystem/doc/reference.html#Class-template- Basispfad). –

+0

@ Robᵩ: Diese Dokumente sind fast drei Jahre alt. Die [_current_docs] (http://www.boost.org/doc/libs/1_50_0/libs/filesystem/doc/reference.html#path-native-format-observers) erwähnen es. ; -] (Dies wurde wahrscheinlich in FileSystem v3 hinzugefügt.) – ildjarn

0

Expressions

OutputDebugString(file.path().c_str()) 

und

OutputDebugString(file.c_str()) 

sind ähnlich, dass sie rufen beide effektiv c_str() Methode auf einem temporären std::string Objekt und versuchen, das Ergebnis dieses Aufrufs zu verwenden. Der erste nennt es direkt file.path().c_str() Teilausdruck. Die zweite macht es implizit: innerhalb FileReference::c_str() Methode.

Im ersten Fall wird das temporäre Objekt std::string explizit durch file.path() Aufruf als unmittelbarer Teil des gesamten Ausdrucks erstellt. In Übereinstimmung mit den Regeln der Sprache erstreckt sich die Lebensdauer dieses temporären Objekts bis zum Ende des gesamten Ausdrucks, weshalb die temporären und das Ergebnis des c_str() Rufes in ganz gültig bleiben. Im zweiten Fall wird das temporäre std::string Objekt innerhalb der FileReference::c_str() Methode erstellt. Das temporäre Objekt zerstört wird, wenn diese Methode zurückgibt, was bedeutet, dass FileReference::c_str() einen Zeiger zurück zu „tot“ Daten. Dies ist der Grund für den fraglichen "Müll".