初學者對於 MFC 中 CString 常見的三個問題

開發 MFC 視窗程式時,很常會使用到 CString 來操作字串,

然而很多 MFC 的初學者雖然會使用 CString,但卻對於 CString 有很多疑問,

以下是我針對初學者對於 CString 最常見的三個問題之說明 ~

Q. 在一個 function 裡宣告 CString 變數,這個變數是儲存在 Stack 還是 Heap ?

一個變數儲存在哪裡取決於這個變數的宣告方式,

如果一個變數是全域變數或 static 變數,那這個變數是儲存在 data,

如果一個變數是區域變數,那這個變數是儲存 stack,

如果一個變數是藉由執行時 new/malloc 產生,那這個變數是儲存 heap。

CString 也不例外,一樣會 follow 以上的規則。

Q. CString str = _T("1111111111"); sizeof(str) 是多大呢? sizeof(CString) 呢? sizeof(CString *) 呢?

這題是很多 MFC 初學者會回答錯的事情,最常聽到的錯誤答案是字串多大 CString 就多大。

回答這個問題之前,我們必須要清楚的知道 CString 是一個 Class,

而一個 Class 的大小取決於這個 Class 的 member data,

因此 CString 也不例外,CString 的大小取決於 CString 的 member data,

而 CString 的 member data 只有 PXSTR m_pszData,

所以 sizeof(str) = sizeof(CString) = sizeof(m_pszData) => 32 位元答案是 4, 64 位答案則是 8

sizeof(CString *) => 32 位元答案是 4, 64 位答案則是 8。

Q. 一個 Function 的參數中有 CString,它會如何傳遞?

先來幫大家複習一下 C++傳遞參數的三種方法,CString 也是一樣藉由這三種方式傳遞。

1. Pass by value (Call by value) => void function(CString str);

這一種方式會在傳遞參數之前建立一份 Copy 的 CString,

所以在 function 裡面實際訪問的是 Copy 出來的 CString,

這時候有些人會詢問這樣會不會很浪費記憶體呢?

答案是不會,因為 CString 的 Copy Assignment 在沒有被 lock 的情況下,

它會直接共享 m_pszData,也就是說二個 CString 共享 m_pszData。

這時候有些人又會接著問,

如果在 callee 內改到字串,那 caller 原本的 CString 不是也會被改變嗎?

答案是,MFC 會在改變字串的時候檢查 m_pszData 在多少個地方共享,

如果多地方共享的情況下,那麼改變字串的地方會去 allocate 新的 m_pszData,

所以這就是為什麼 CString 直接藉由 Pass by value 傳遞也不會浪費記憶體或慢的原因。

2. Pass by pointer (Call by pointer) => void function(CString* str);

這一種方式是直接傳遞 pointer,由於是傳遞 pointer,所以其行為都會改到 caller 的 CString。

3. Pass by reference (Call by reference) => void function(CString& str);

這一種方式是傳遞 reference,由於是傳遞 reference,所以其行為都會改到 caller 的 CString,

不過其實說穿了,這個方式只是 C++ 為了讓使用者寫的時候比較方便 (省去一堆 pointer),

所以讓 Compiler 幫你在編譯的時做轉 pointer 這件事情。

(也就是 Pass by reference 編譯出來的 Assembly 跟 Pass by pointer 行為是一樣的)

留言

這個網誌中的熱門文章

[面試心得] Synology / 群暉 - Product Developr

[面試心得] VICI Holdings / 威旭(高頻交易) - Software Engineer

[面試心得] GoFreight / 聖學科技(Freight Forwarder) - Full-Stack Engineer