Can I reload the CArchive << operator to work with std :: string?

I am using std :: string in my MFC application and I want to save it in the doc Serialize () function. I do not want to store them as CString, because there he writes his own material, and my goal is to create a file that I know is a format and can be read by another application without the need for CString. Therefore, I would like to save my std :: strings as a string length of 4 bytes (int), followed by a buffer of this 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 small and I have to allocate temp bfr to read the line. First, can I read a string directly in std :: string without a temporary buffer? Secondly, I can overload the <buffers for std :: string / CArchive, so I can just use ar <String? In general, is there a better way to read / write std :: string using a CArchive object?

+6
source share
5 answers

Try:

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

Technically, &theString[0] cannot point to a continuous character buffer, but the C ++ committee did a poll and found that all existing implementations work this way.

+1
source

You can create inplace CString from stl string and serialize it. Sort of:

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

You can put this in a global operator overload so you can just

 ar << my_c_string; 

from anywhere:

 CArchive& operator<<(CArchive rhs, string lhs) { CString c_string(lhs.c_str()); rhs << c_string; } 
+1
source

It's probably best to write the data as a CString for various reasons, but if you need to convert a String (m_sString) string to an ASCII character string, something like this might 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); } } 
+1
source

If you are working with a library that only works with c-style strings, there is no way to safely write directly to std :: string . This 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); 

Most likely, this will work, but later it may create some subtle, hard-to-reach errors. Of course, your question implies that you have profiled your code and found out that creating a buffer and copying data twice is actually the bottleneck of your code. If you have not done so, then you should not worry about inefficiency.

0
source

I assume that you can break the STL rules and inherit std::string and add your own buffer receiver / setter. Then override the copy constructor for std :: string and pass the ownership of the buffer.

0
source

Source: https://habr.com/ru/post/897477/


All Articles