6 Stimmen

Kann ich den Operator CArchive << überladen, um mit std::string zu arbeiten?

Ich verwende std::string in meiner MFC-Anwendung und ich möchte sie in der Funktion Serialize() von doc speichern. Ich möchte sie nicht als CString speichern, weil es sein eigenes Zeug dort hinein schreibt und mein Ziel ist es, eine Datei zu erstellen, deren Format ich kenne und die von anderen Anwendungen gelesen werden kann, ohne CString zu benötigen. Ich möchte also meine std::strings als 4 Bytes (int) Stringlänge speichern, gefolgt von einem Puffer dieser Größe, der den String enthält.

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;
    }
}

Der obige Code ist nicht gut und ich muss eine temporäre bfr zuweisen, um die Zeichenfolge zu lesen. Erstens kann ich die Zeichenkette direkt in std::string ohne den temporären Puffer lesen? Zweitens kann ich den << Puffer für std::string / CArchive überladen, so dass ich einfach ar << theString verwenden kann? Gibt es insgesamt eine bessere Möglichkeit, std::string mit dem CArchive-Objekt zu lesen/schreiben?

2voto

Ricibob Punkte 7297

Sie könnten einen Inplace-CString aus Ihrem stl-String erstellen und diesen serialisieren. Etwas wie:

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

Sie könnten dies in einem globalen Operator Überlastung setzen, so dass es können Sie nur

ar << my_c_string;

von überall her z.B.:

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

1voto

Mark Ransom Punkte 283960

Versuchen Sie es:

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

Technisch &theString[0] ist nicht garantiert, dass es auf einen zusammenhängenden Zeichenpuffer zeigt, aber das C++-Komitee hat eine Umfrage durchgeführt und festgestellt, dass alle vorhandenen Implementierungen auf diese Weise arbeiten.

1voto

Duncan Punkte 11

Seine wahrscheinlich besser, die Daten als CString aus verschiedenen Gründen zu schreiben, aber wenn Sie Ihre Zeichenfolge (m_sString) in eine ASCII-Zeichenfolge konvertieren müssen, vielleicht so etwas wie dies für Sie arbeiten wird...

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

1voto

Frank Heimes Punkte 100

Nur um ein voll funktionsfähiges und (hoffentlich) korrektes Beispiel für beides hinzuzufügen std::string y std::wstring :

#include <string>
#include <gsl/gsl>

template <typename Char>
CArchive& operator<<(CArchive& ar, const std::basic_string<Char>& rhs)
{
    const auto size = rhs.size();
    ar << size;
    ar.Write(rhs.data(), gsl::narrow_cast<UINT>(size) * sizeof(Char));
    return ar;
}

template <typename Char>
CArchive& operator>>(CArchive& ar, std::basic_string<Char>& rhs)
{
    size_t size{};
    ar >> size;
    rhs.resize(size);
    ar.Read(rhs.data(), gsl::narrow_cast<UINT>(size) * sizeof(Char));
    return ar;
}

Schreiben ...

std::wstring ws{ L"wide string" };
ar << ws;

std::string ns{ L"narrow string" };
ar << ns;

Lesen ...

std::wstring ws;
ar >> ws;

std::string ns;
ar >> ns;

0voto

David Nehme Punkte 21073

Wenn Sie mit einer Bibliothek arbeiten, die nur mit Strings im C-Stil arbeitet, gibt es keine Möglichkeit, die direkt in den std::string schreiben . Dieses Problem ist in C++0x behoben. Also etwas wie

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

Das würde wahrscheinlich funktionieren, könnte aber später zu einigen subtilen, schwer zu verfolgenden Fehlern führen. Ihre Frage setzt natürlich voraus, dass Sie ein Profil Ihres Codes erstellt haben und herausgefunden haben, dass die Erstellung des Puffers und das doppelte Kopieren der Daten tatsächlich ein Engpass in Ihrem Code ist. Wenn das nicht der Fall ist, sollten Sie sich noch nicht über Ineffizienzen aufregen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X