iT邦幫忙

2025 iThome 鐵人賽

DAY 12
2
Software Development

30 天 Effective C++ 大挑戰!!系列 第 12

[Day 12] 中場休息 Q&A小測驗!!

  • 分享至 

  • xImage
  •  

《Effective C++》的閱讀進度依然過半,難度當然也逐漸提升。於是每個章節結束,就來個小考題複習一下吧!

Q1. 根據知識點 26 的建議,以下程式碼有什麼效率上的問題?

std::string encryptPassword(const std::string& password)
{
    using namespace std;
    string encrypted;
    if(password.length() < MinimumPasswordLength)
    {
        throw logic_error ("Password is too short"); 
    }
    // encryption logic here...
    return encrypted;
}

A) 該函式的回傳值未使用 reference。
B) 例外 exception 的時機過晚。
C) 變數 encrypted 並未初始化值。
D) 該函式不應使用 using namespace std;
E) 變數 encrypted 過早被定義。

此程式碼中,變數 encrypted 在尚未確認需要之前就被定義,但實際上只有在驗證密碼長度後才會被使用。如果在檢查密碼長度時拋出了 exception,那 encrypted 的建構和解構都變得完全沒有意義。

若能將 encrypted 的定義延後執行,能有效避免額外的建構與資源浪費。透過這種調整,可以提升程式的效率,避免不必要的資源建構與釋放。

Q2. 舊式轉型與 static_cast, dynamic_cast 等 C++ 型別轉換相比,下列敘述何者正確?
A) 舊式轉型可強制類型轉換,總是比 C++ 型別轉換更安全。
B) C++ 型別轉換在程式碼中更容易辨識,並能讓編譯器檢測出更多錯誤情境。
C) 在程式碼的可讀性上,C++ 型別轉換與舊式轉型沒有任何區別。
D) 使用 C++ 常見的 4 種轉型類型時,皆能移除 const 限制。
E) 舊式轉型更受偏好,因為它們更具明確性。

C++ 型別轉換在程式碼中更容易辨認,同時每種轉型有明確且限定的用途,讓編譯器可以更有效地檢查錯誤。

C++ 型別轉換的優勢在於明確性安全性,透過清楚的轉型目標和編譯器的協助,能顯著降低程式中的潛在異常。例如:只有const_cast 可以移除 const 限制;若以 static_cast 嘗試進行無效的轉型,則編譯階段會觸發錯誤。

相比之下,(type)object 舊式轉型較不具明確性,容易隱藏微妙的錯誤因而更危險。尤其在處理複雜類型時可能導致意想不到的行為,因此舊式轉型在現代 C++ 中較少被推薦。

Q3. 以下是 YoyoPicture::changeBackground 的實作範例:

void YoyoPicture::changeBackground(std::istream& imgSrc)
{
    lock(&mutex);
    delete bgImage;
    ++imageChanges;
    bgImage = new Image(imgSrc)
    unlock(&mutex);
}

以 exception-safe 的角度來看,該函式實作中最大的弱點是什麼?
A) 程式碼過於冗長,可讀性較低。
B) 某些狀況下可能會導致資料結構損毀。
C) bgImage 並未使用智慧指標。
D) mutex 應宣告為 class 的成員變數。
E) 在刪除舊圖像前就遞增了 imageChanges 計數。

如果 new Image(imgSrc) 發生異常,mutex 可能無法執行 unlock,導致鎖資源無法釋放。而當 bgImage 已被刪除,但此時若未完成新圖像的建構,bgImage 會變成一個dangling pointer ,可能指向已經不存在的記憶體。

如果發生 exception,函式應保證至少滿足基本的安全性 —— 物件保持一致性且沒有資源洩漏。可使用 知識點 13 開始不斷提到的 RAII 模式和智慧指標來管理資源。例如用 std::unique_ptrstd::shared_ptr 自動管理記憶體釋放,並搭配 std::lock_guardstd::unique_lock 等功能的智慧鎖。

改進後的程式碼範例如下:

void YoyoPicture::changeBackground(std::istream& imgSrc)
{
    std::lock_guard<std::mutex> guard(mutex);  // 自動管理鎖
    std::unique_ptr<Image> newImage(new Image(imgSrc));  // 智慧指標管理記憶體
    bgImage.swap(newImage);  // 更新圖像指標
    ++imageChanges;          // 更新計數器
}

Q4. 以下關於 C++ 中的 pimpl 技巧,哪一項不是它的優點?
A) 通過隱藏實現細節,減少編譯依賴。
B) 能修改 implementation,而無需重新編譯客戶端程式。
C) 能真正分離 interface 及 implementation。
D) 消除與動態記憶體分配相關的所有執行期負擔。
E) 避免客戶端依賴 implementation 細節。

pimpl 能有效減少編譯依賴,實現 interface 與 implementation 的分離。其避免客戶端對實現細節的依賴,在提升封裝性方面十分有效。然而它並不能消除執行期的負擔。

事實上正好相反,pimpl 會帶來一些額外的效能負擔。

  • 動態記憶體分配:通常需要用 new 分配記憶體來管理 implementation。
  • 指標間接操作:透過指標來存取內部 implementation,增加了執行效能的開銷。

上一篇
[Day 11] Implementations II
下一篇
[Day 13] 綜合大會考!! —— 期中篇
系列文
30 天 Effective C++ 大挑戰!!30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言