我可以超载 CArchive <<运算符与 std::string 一起使用吗?

发布于 2024-12-05 00:17:01 字数 902 浏览 0 评论 0 原文

我在 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 的缓冲区,因此我可以简单地使用 ar <<字符串?总的来说,有没有更好的方法使用 CArchive 对象读取/写入 std::string ?

I am using std::string in my MFC application and I want to store it in doc's Serialize() function. I don't want to store them as CString because it writes its own stuff in there and my goal is to create a file that I know the format of and can be read by other application without needing CString. So I would like to store my std::strings as 4 bytes (int) string length followed by buffer of that size containing the 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;
    }
}

The above code is not great and I have to allocate a temp bfr to read the string. First can I read the string directly into std::string without the temp buffer? Secondly can I overload the << buffer for std::string / CArchive so I can simply use ar << theString? Overall is there a better way to read/write std::string using CArchive object?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

嘿嘿嘿 2024-12-12 00:17:01

您可以从 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;
}

You could build an inplace CString from your stl string and serialize that. Something like:

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

You could put this in a global operater overload so it can you can just

ar << my_c_string;

from anywhere eg:

CArchive& operator<<(CArchive rhs, string lhs) {
    CString c_string(lhs.c_str());
    rhs << c_string;
}
2024-12-12 00:17:01

尝试:

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

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

Try:

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

Technically &theString[0] is not guaranteed to point to a contiguous character buffer, but the C++ committee did a survey and found that all existing implementations work this way.

╰沐子 2024-12-12 00:17:01

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

Its probably better to write the data as a CString for various reasons, but if you have to convert your String (m_sString) into an ASCII character string, maybe something like this will work for you...

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);
    }
}
尤怨 2024-12-12 00:17:01

只是为 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;

Just to add a fully functional and correct example (hopefully) for both std::string and 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;
}

Writing ...

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

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

Reading ...

std::wstring ws;
ar >> ws;

std::string ns;
ar >> ns;
琴流音 2024-12-12 00:17:01

如果您使用的库仅适用于 c 样式字符串,则无法安全 直接写入 std::string。该问题已在 C++0x 中修复。
所以像这样的东西

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

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

If you are working with a library that only works with c-style strings, there is no way to safely write directly to the std::string. That issue is fixed in C++0x.
So something like

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

Would probably work, but it could create some subtle, hard-to-track bugs later on.
Of course your question implies that you have profiled your code and figured out that creating the buffer and copying the data twice is actually a bottleneck in your code. If you haven't, then you shouldn't be fretting about inefficiencies yet.

别闹i 2024-12-12 00:17:01

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

I suppose you could violate STL guidelines and inherit std::string and add your own buffer getter/setter. Then override the copy constructor for std::string and transfer ownership of the buffer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文