我們正在將一個舊的 MFC 專案從 VS2010 升級到 VS2017,并且在將資料分配給使用 ZeroMemory 清除的結構內的 std::string 時,我們發現了不同的行為。
我創建了一個簡單的 MFC 程式來復制該問題。
std::string getStrData() {
std::string temp = "world";
return temp;
}
CMainFrame::CMainFrame()
{
struct mystruct{
std::string mystr_in1;
std::string mystr_in2;
};
std::string mystr_out = "hello";
mystruct* sttemp = new mystruct();
ZeroMemory(sttemp, sizeof(mystruct)); // <-- we think this is bad
sttemp->mystr_in1 = mystr_out; // <-- VS2010: "hello" is assigned, but VS2017: garbage is assigned
sttemp->mystr_in2 = getStrData(); // <-- VS2010 and VS2017: "world" is assigned
}
在 VS2010 中,mystr_out ("hello") 的值被正確地分配給了 mystr_in1。但是在 VS2017 中,垃圾資料被分配給了 mystr_in1。我在 StackOverflow 中讀到了類似的問題,在這種情況下執行 ZeroMemory 會破壞 std::string,所以我們認為這是問題的原因。但在 mystr_in2 中,它能夠在 VS2010 和 VS2017 中正確分配“世界”。
如果有人可以解釋,我有兩個關于這種行為的問題。
對于第一種情況(mystr_in1),為什么在 VS2010 和 VS2017 中編譯的代碼有不同的行為?VS2017中是否有某種專案設定來解決這個問題?升級老VS2010專案時,我們只是在VS2017中打開VS2010解決方案,選擇升級解決方案。(我們的大多數舊專案只要這樣做就沒有問題)
對于第二種情況(mystr_in2),它應該與第一種情況相同(?),但分配給它的 std::string 是從函式回傳的。這與第一種情況有什么不同,它也分配了一個 std::string?
uj5u.com熱心網友回復:
代碼從來都不是正確的。通過將文字零值寫入記憶體來初始化物件沒有也從未有任何明確定義的行為。在實踐中,對于可復制的型別,你經常可以僥幸逃脫,但行為仍然是未定義的。然而,有問題的代碼不能為自己宣告那個灰色區域:不是一般可復制的。mystruct
觀察到的行為變化很可能是由于 SSO(短字串優化)造成的,盡管要推斷從未有任何明確指定的行為開始的行為變化是沒有實際意義的。
幸運的是,修復很簡單:只需洗掉ZeroMemory呼叫即可。默認構造的mystruct將具有默認構造的std::string成員,因此沒有理由再次“初始化”它們。
1 無論如何,我相信。這畢竟是 C ,而且它的復雜性似乎已經遠遠超出了平均智力水平。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/447709.html
標籤:C 视觉工作室 2010 视觉工作室 2017 mfc
