Могу ли я перегрузить оператор CArchive << для работы с std :: string? - PullRequest
6 голосов
/ 16 сентября 2011

Я использую std :: string в своем приложении MFC и хочу сохранить его в функции Serialize () документа. Я не хочу хранить их как CString, потому что там они пишут свои собственные вещи, и моя цель - создать файл, формат которого мне известен, и который может быть прочитан другим приложением без необходимости использования CString. Поэтому я хотел бы хранить мои std :: strings как строку длиной 4 байта (int), за которой следует буфер такого размера, содержащий строку.

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

Приведенный выше код не очень хорош, и я должен выделить временную BFR для чтения строки. Сначала я могу прочитать строку непосредственно в std :: string без временного буфера? Во-вторых, я могу перегрузить << буфер для std :: string / CArchive, чтобы я мог просто использовать ar << theString? В целом, есть ли лучший способ чтения / записи std :: string с использованием объекта CArchive? </p>

Ответы [ 5 ]

1 голос
/ 04 сентября 2016

Вероятно, лучше по разным причинам записывать данные в виде CString, но если вам нужно преобразовать вашу String (m_sString) в символьную строку ASCII, возможно, что-то подобное будет работать для вас ...

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);
    }
}
1 голос
/ 28 сентября 2011

Вы можете создать встроенную строку CString из строки stl и сериализовать ее. Что-то вроде:

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

Вы можете поместить это в глобальную перегрузку оператора, чтобы вы могли просто

ar << my_c_string;

из любого места, например:

CArchive& operator<<(CArchive rhs, string lhs) {
    CString c_string(lhs.c_str());
    rhs << c_string;
}
1 голос
/ 16 сентября 2011

Попробуйте:

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

Технически &theString[0] не гарантирует указание на непрерывный буфер символов, но комитет C ++ провел опрос и обнаружил, что все существующие реализации работают таким образом.

0 голосов
/ 26 сентября 2011

Полагаю, вы могли нарушить правила STL и наследовать std::string и добавить свой собственный буферный метод получения / установки.Затем переопределите конструктор копирования для std :: string и передайте владение буфером.

0 голосов
/ 16 сентября 2011

Если вы работаете с библиотекой, которая работает только со строками в стиле c, невозможно безопасно записать напрямую в std :: string . Эта проблема исправлена ​​в C ++ 0x. Так что-то вроде

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

Возможно, это сработает, но позже это может привести к появлению каких-то неуловимых, трудно отслеживаемых ошибок. Конечно, ваш вопрос подразумевает, что вы профилировали свой код и выяснили, что создание буфера и двойное копирование данных на самом деле является узким местом в вашем коде. Если нет, то вам не стоит беспокоиться о неэффективности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...