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?
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);
}
}
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.
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;
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;
}
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 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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.