2011-09-16 77 views
6

我在我的MFC應用程序中使用std :: string,我想將它存儲在doc的Serialize()函數中。我不想將它們存儲爲CString,因爲它將自己的東西寫入其中,我的目標是創建一個文件,我知道其他應用程序的格式並可以在不需要CString的情況下讀取它。所以我想將我的std :: strings存儲爲4個字節(int)的字符串長度,接着是包含字符串的那個大小的緩衝區。我可以重載CArchive <<運算符以使用std :: 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; 
    } 
} 

上面的代碼也不是很大,我必須分配一個臨時BFR閱讀的字符串。首先,我可以直接將字符串讀入不帶臨時緩衝區的std :: string中?其次,我可以重載std :: string/CArchive緩衝區的<,所以我可以簡單地使用ar < < theString?總體來說有更好的方法來讀/寫使用CArchive對象的std :: string嗎?

回答

0

如果您正在使用僅適用於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); 

可能會工作,但它可能以後產生一些微妙的,難以跟蹤的錯誤。 當然你的問題意味着你已經對你的代碼進行了剖析,並發現創建緩衝區和兩次複製數據實際上是你的代碼中的一個瓶頸。如果你還沒有,那麼你不應該對效率低下感到擔憂。

+0

我試過這個,但c_str()返回'const char *',這是一個問題。我可能可以將它轉換爲簡單的'char *',但這會違反c_str()函數。 – zar

+1

因此,「不要這樣做」的評論。你可以使用'std :: vector '或者因爲你在MFC土地使用'CString' – AJG85

1

嘗試:

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

技術上&theString[0]不保證指向一個連續的字符緩衝區,但C++委員會做了一個調查,發現所有現有的實現以這種方式工作。

0

我想你可能違反STL指導原則,繼承std::string並添加你自己的緩衝區獲取器/設置器。然後覆蓋std :: string的拷貝構造函數並轉移緩衝區的所有權。

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; 
} 
1

它可能更好地寫入數據作爲一個CString的各種原因,但如果你必須將您的字符串(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); 
    } 
}