2011-09-16 9 views
6

Estoy usando std :: string en mi aplicación MFC y quiero almacenarlo en la función Serialize() del documento. No quiero almacenarlos como CString porque escribe sus propias cosas allí y mi objetivo es crear un archivo que conozca el formato y pueda ser leído por otra aplicación sin necesidad de CString. Así que me gustaría almacenar mis std :: cadenas como una longitud de cadena de 4 bytes (int) seguida por un buffer de ese tamaño que contiene la cadena.¿Puedo sobrecargar el operador CArchive << para trabajar 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; 
    } 
} 

El código anterior no es excelente y tengo que asignar una temperatura bfr para leer la cadena. Primero, ¿puedo leer la cadena directamente en std :: string sin el buffer temporal? En segundo lugar, ¿puedo sobrecargar el buffer < < para std :: string/CArchive entonces puedo simplemente usar ar < < theString? En general, ¿hay una mejor manera de leer/escribir std :: string utilizando el objeto CArchive?

Respuesta

0

Si está trabajando con una biblioteca que solo funciona con cadenas de estilo c, no hay forma segura de write directly to the std::string. Ese problema está arreglado en C++ 0x. Así algo así como

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

probablemente funcionaría, pero podría crear algunos errores sutiles, difíciles de pista más adelante. Por supuesto, su pregunta implica que ha perfilado su código y se dio cuenta de que crear el búfer y copiar los datos dos veces es en realidad un cuello de botella en su código. Si no lo has hecho, entonces no deberías preocuparte por las ineficiencias.

+0

He intentado esto pero c_str() devuelve un 'const char *' y eso es un problema. Probablemente podría encasillarlo para simplemente 'char *' pero eso violaría algo la función c_str(). – zar

+1

Por lo tanto, el comentario "no hagas esto". Puede usar un 'std :: vector ' o dado que está en el uso de la tierra MFC 'CString' – AJG85

1

Probar:

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

Técnicamente &theString[0] sin garantía para que apunte a un búfer de caracteres contiguos, pero el comité C++ hicieron una encuesta y encontró que todas las implementaciones existentes funcionan de esta manera.

0

Supongo que puede violar las pautas de STL y heredarstd::string y agregar su propio buffer getter/setter. A continuación, anule el constructor de copia para std :: string y transfiera la propiedad del búfer.

1

Puedes construir un CString en el lugar desde tu stl y serializarlo. Algo así como:

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

se puede poner esto en una sobrecarga de operater mundial por lo que puede usted puede simplemente

ar << my_c_string; 

desde cualquier lugar, por ejemplo:

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

Es probablemente mejor escribir los datos como CString por varias razones, pero si tiene que convertir su String (m_sString) en una cadena de caracteres ASCII, tal vez algo así funcione para usted ...

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); 
    } 
} 
Cuestiones relacionadas