我可以重载 CArchive << 运算符以使用 std::string 吗?

Posted

技术标签:

【中文标题】我可以重载 CArchive << 运算符以使用 std::string 吗?【英文标题】:Can I overload CArchive << operator to work with std::string? 【发布时间】:2011-09-16 14:49:35 【问题描述】:

我在我的 MFC 应用程序中使用 std::string,我想将它存储在 doc 的 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 的

【问题讨论】:

【参考方案1】:

您可以从您的 stl 字符串构建一个就地 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;

【讨论】:

【参考方案2】:

试试:

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

从技术上讲,&amp;theString[0] 不能保证指向一个连续的字符缓冲区,但 C++ 委员会进行了一项调查,发现所有现有实现都以这种方式工作。

【讨论】:

【参考方案3】:

出于各种原因,将数据写成 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);
    

【讨论】:

【参考方案4】:

如果您使用的库仅适用于 c 样式字符串,则无法安全地使用 write directly to the std::string。该问题已在 C++0x 中修复。 所以像

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

可能会起作用,但它可能会在以后产生一些微妙的、难以跟踪的错误。 当然,您的问题意味着您已经分析了代码并发现创建缓冲区和复制数据两次实际上是代码中的瓶颈。如果你还没有,那么你不应该为效率低下而烦恼。

【讨论】:

我已经尝试过了,但是 c_str() 返回一个 'const char *',这是一个问题。我可能可以将它简单地转换为 'char *' 但这会有点违反 c_str() 函数。 因此“不要这样做”评论。您可以使用 std::vector&lt;char&gt; 或者因为您在 MFC 土地使用 CString【参考方案5】:

我想您可能会违反 STL 准则和 inherit std::string 并添加自己的缓冲区 getter/setter。然后重写 std::string 的复制构造函数并转移缓冲区的所有权。

【讨论】:

以上是关于我可以重载 CArchive << 运算符以使用 std::string 吗?的主要内容,如果未能解决你的问题,请参考以下文章

读取使用 CArchive Ar(&SaveDataStoreDetail, CArchive::store) 存储的数据;

从 CArchive 读取 WORD 变量并同时转换为 int

CArchive (MFC) 到 JSON?

从 CArchive 文件中检索信息

CFile与CArchive区别

反序列化在 java 中使用 mfc CArchive 创建的文件