簡體   English   中英

我可以重載 CArchive << 運算符以使用 std::string 嗎?

[英]Can I overload CArchive << operator to work with std::string?

我在我的 MFC 應用程序中使用 std::string,我想將它存儲在文檔的 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? 總的來說,有沒有更好的方法來使用 CArchive 對象讀/寫 std::string?

由於各種原因,將數據寫為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);
    }
}

嘗試:

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

技術上&theString[0]不能保證指向一個連續的字符緩沖區,但是C ++委員會做了一項調查,發現所有現有的實現都是這樣的。

只是為std::stringstd::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;
}

寫作...

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

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

讀...

std::wstring ws;
ar >> ws;

std::string ns;
ar >> ns;

您可以從stl字符串構建一個inplace CString並序列化它。 就像是:

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

如果您正在使用僅適用於c風格字符串的庫,則無法安全地直接寫入std :: string 該問題在C ++ 0x中得到修復。 所以像

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

可能會工作,但它可能會在以后創建一些微妙的,難以跟蹤的錯誤。 當然,你的問題意味着你已經分析了你的代碼,並發現創建緩沖區和復制數據兩次實際上是代碼中的瓶頸。 如果你還沒有,那么你不應該擔心效率低下。

我想你可能違反STL指南並繼承 std::string並添加你自己的緩沖區getter / setter。 然后覆蓋std :: string的復制構造函數並轉移緩沖區的所有權。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM