我可以重载 CArchive <<运算符来处理 std::string 吗?
Can I overload CArchive << operator to work with std::string?
我在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 <<theString吗?总的来说,是否有更好的方法来读/写std::string使用CArchive对象?
您可以从stl字符串中构建一个inplace CString并对其进行序列化。例如:
CString c_string(my_stl_string.c_str();
ar << c_string;
你可以把它放在全局操作符重载中所以你可以直接
ar << my_c_string;
from anywhere例如:
CArchive& operator<<(CArchive rhs, string lhs) {
CString c_string(lhs.c_str());
rhs << c_string;
}
尝试:
theString.resize(size);
ar.Read(&theString[0], size);
从技术上讲,&theString[0]
不能保证指向一个连续的字符缓冲区,但是c++委员会做了一项调查,发现所有现有的实现都是这样工作的。
出于各种原因,最好将数据写为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);
}
}
只是为std::string
和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;
}
写作……
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;
如果您使用的库只处理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的复制构造函数并转移缓冲区的所有权。
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- 呼叫运营商<<临时
- cppcheck在const std::string[]上引发警告
- 将std::string传递给WriteConsole API
- 如何防止clang格式在流运算符调用之间添加换行符<<
- 为std::string的某个索引赋值
- <<操作员在下面的行中工作
- std中有类似find_last_of的函数,而string中没有
- 使用 std::string () const 函数启动线程或未来
- 使用char类型将decimal转换为string,将string转换为decimal
- 迭代和比较映射<字符串、矢量<string>> c++ 中的值
- 当我们进行一些操作时,应该使用什么'std::string'或'std::stringstream'?
- 将向量解析<string>为字符串
- 'string.assign(string.data(), 5)' 是明确定义的还是 UB?
- 如何更改大小(std::string)
- "string.h"在构建适用于iOS的qt应用程序中找不到消息
- C++:如何将 unix 时间的字符串转换为 *tm?(使用时间错误:"cannot convert 'String' to 'tm*' ")
- std::string 的对象真的可以移动吗?
- 与'operator='不匹配(操作数类型'String'且"void")
- SegFault 同时使用 std::string::operator+= 和函数作为参数