2011-09-16 10 views
6

Sto usando std :: string nella mia applicazione MFC e voglio conservarlo in funzione di Doc Serialize(). Non voglio memorizzarli come CString perché scrive le proprie cose lì dentro e il mio obiettivo è creare un file che conosca il formato e possa essere letto da un'altra applicazione senza aver bisogno di CString. Quindi vorrei memorizzare il mio std :: stringhe come 4 byte (int) lunghezza della stringa seguita da buffer di quella dimensione contenente la stringa.Posso sovraccaricare l'operatore CArchive << per lavorare con std :: string?

void CMyDoc::Serialize(CArchive& ar) 
{ 
    std::string theString; 

    if (ar.IsStoring()) 
    { 
     // TODO: add storing code here 
     int size = theString.size(); 
     ar << size; 
     ar.Write(theString.c_str(), size); 

    } 
    else 
    { 
     // TODO: add loading code here 
     int size = 0; 
     ar >> size; 
     char * bfr = new char[ size ]; 
     ar.Read(bfr, size); 
     theString = bfr; 
     delete [] bfr; 
    } 
} 

Il codice di cui sopra non è eccezionale e devo assegnare un bfr temporaneo per leggere la stringa. Per prima cosa posso leggere la stringa direttamente in std :: string senza il buffer temporaneo? Secondariamente posso sovraccaricare il buffer < < per std :: string/CArchive quindi può semplicemente utilizzare ar < < TheString? Nel complesso c'è un modo migliore per leggere/scrivere std :: string usando l'oggetto CArchive?

risposta

0

Se si sta lavorando con una biblioteca che funziona solo con le stringhe c-stile, non c'è modo per write directly to the std::string in modo sicuro. Questo problema è stato risolto in C++ 0x. Quindi qualcosa di simile

// NOT PORTABLE, don't do this 
theString.resize(size); 
ar.Read(const_cast<char *>(theString.c_str(), size); 

probabilmente funzionerebbe, ma potrebbe creare alcuni sottili, bug difficili da pista in seguito. Naturalmente la domanda implica che si è profilato il codice e capito che la creazione di buffer e copiare i dati due volte in realtà è un collo di bottiglia nel codice. Se non lo hai, allora non dovresti essere ancora preoccupato per le inefficienze.

+0

Ho provato questo ma c_str() restituisce un 'const char *' e questo è un problema. Probabilmente avrei potuto convertirlo semplicemente in "char *", ma ciò avrebbe in qualche modo violato la funzione c_str(). – zar

+1

Quindi il commento "non fare questo". Puoi usare un 'std :: vector ' o dato che sei in terra MFC usa 'CString' – AJG85

1

Prova:

theString.resize(size); 
ar.Read(&theString[0], size); 

Tecnicamente &theString[0] non è garantito per puntare a un buffer di caratteri contigui, ma il comitato C++ ha fatto un sondaggio e ha scoperto che tutte le implementazioni esistenti funzionano in questo modo.

0

Suppongo che si possa violare le linee guida STL e ereditarestd::string e aggiungere il proprio buffer di getter/setter. Quindi eseguire l'override del costruttore di copie per std :: string e trasferire la proprietà del buffer.

1

Si potrebbe costruire un inplace CString dalla stringa STL e serializzare che. Qualcosa di simile:

CString c_string(my_stl_string.c_str(); 
ar << c_string; 

Si potrebbe mettere questo in un sovraccarico di operater globale in modo che possa si può solo

ar << my_c_string; 

da qualsiasi esempio:

CArchive& operator<<(CArchive rhs, string lhs) { 
    CString c_string(lhs.c_str()); 
    rhs << c_string; 
} 
1

sua probabilmente meglio scrivere i dati come CString per vari motivi, ma se si deve convertire il vostro String (m_sString) in una stringa di caratteri ASCII, forse qualcosa di simile a questo lavoro per voi ...

void myclass::Serialize(CArchive & ar) 
{ 
    CHAR* buf; 
    DWORD len; 
    if (ar.IsStoring()) // Writing 
    { 
     len = m_sString.GetLength(); // Instead of null terminated string, store size. 
     ar << len; 
     buf = (CHAR*)malloc(len); 
     WideCharToMultiByte(CP_UTF8, 0, m_sString, len, buf, len, NULL, NULL); // Convert wide to single bytes 
     ar.Write(buf, len); // Write ascii chars 
     free(buf); 
    } 
    else // Reading 
    { 
     ar >> len; 
     buf = (CHAR*)malloc(len); 
     ar.Read(buf, len); // Read ascii string 
     MultiByteToWideChar(CP_UTF8, 0, buf, len, m_sString.GetBufferSetLength(len), len); // Convert ascii bytes to CString wide bytes 
     free(buf); 
    } 
} 
Problemi correlati