2012-07-06 9 views
6

Sto ancora imparando C++, quindi per favore portami con me. Sto scrivendo un semplice wrapper per incrementare i percorsi del filesystem - Sto avendo strani problemi con il ritorno di stringhe temporanee. Ecco il mio semplice classe (questo non è esatto, ma abbastanza vicino):Std temporaneo: stringhe che restituiscono spazzatura

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; 

} 

Con il codice di prova poco sotto:

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

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

Sono abbastanza sicuro che questo ha a che fare con temporanei, ma io non riesco a capire perché sarebbe - non dovrebbe essere tutto copiato correttamente?

+0

qual è la fonte di 'OutputDebugString()'? –

+2

Cringato a 'typedef''ing proprio' CString' ... – Blindy

+1

@OttoAllmendinger - È una [API Windows] (http://msdn.microsoft.com/en-us/library/windows/desktop/aa363362 (v = vs.85) .aspx). –

risposta

4

Sembra che mPath.string() restituisca una stringa in base al valore. L'oggetto stringa temporaneo viene distrutto non appena viene restituito FileReference :: c_str(), quindi il suo c_str() non è più valido. Con tale modello, non è possibile creare una funzione c_str() senza introdurre una sorta di variabile di livello statica o di classe per la stringa.

considerare le seguenti alternative:

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

o

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

Un uso valido per il primo suggerimento sarebbe 'OutputDebugString (file.str(). c_str()); ' –

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

mPath.string() restituisce una copia di un std::string. Quella copia è immagazzinata in un temporaneo che sarà distrutto alla fine di questa espressione.

.c_str() restituisce un puntatore alla memoria che verrà distrutto quando la stringa viene distrutta, ossia alla fine di questa espressione.

Si sta restituendo un puntatore alla memoria che è già stato distrutto.

+1

se vuole un puntatore, potrebbe restituire m_path.c_str() – PermanentGuest

+0

@PermanentGuest - sei sicuro? Non riesco a trovare '.c_str()' nel Boost.Filesystem [documentazione] (http://www.boost.org/doc/libs/1_41_0/libs/filesystem/doc/reference.html#Class-template- basic_path). –

+0

@ Rob: quei documenti hanno quasi tre anni. I [_current_documenti] (http://www.boost.org/doc/libs/1_50_0/libs/filesystem/doc/reference.html#path-native-format-observers) lo menzionano. ; -] (Probabilmente è stato aggiunto in FileSystem v3.) – ildjarn

0

Espressioni

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

e

OutputDebugString(file.c_str()) 

sono simili in quanto entrambi chiamano efficacemente c_str() metodo su un oggetto temporaneo std::string e tentano di utilizzare il risultato della chiamata. Il primo lo chiama direttamente come sottoespressione file.path().c_str(). Il secondo lo fa più implicitamente: all'interno del metodo FileReference::c_str().

Nel primo caso l'oggetto temporaneo std::string viene creato esplicitamente dalla chiamata file.path() come parte immediata dell'intera espressione. In conformità con le regole del linguaggio, la durata di tale oggetto temporaneo si estende fino alla fine dell'intera espressione, motivo per cui il periodo temporaneo e il risultato della chiamata c_str() rimangono validi per tutto il tempo.

Nel secondo caso l'oggetto temporaneo std::string viene creato all'interno del metodo FileReference::c_str(). L'oggetto temporaneo viene distrutto quando viene restituito questo metodo, ovvero FileReference::c_str() restituisce un puntatore ai dati "morti". Questa è la ragione per la "spazzatura" in questione.

Problemi correlati