設計與聲明(上)
18.讓接口容易被使用,不易被誤用
“促進正確使用”的辦法包括接口的一致性,以及與內置類型的行爲兼容
“阻止誤用”的辦法包括建立新類型、限制類型上的操作,束縛對象值,以及消除客戶的資源管理責任
shared_ptr支持定製型刪除器。這可防範DLL問題,可被用來自動解除互斥鎖等
- 如果接口要求客戶必須記得做某些事情,就是有着”不正確使用“的傾向
- shared_ptr提供的構造函數接受2個實參,一個是被管理的指針,一個是引用次數變0時將被調用的“刪除器”
- “將原始指針傳遞給pInv構造函數”會比“先將pInv初始化爲null再對它做一次賦值操作”更好
- cross-DLL problem:對象在動態鏈接程序庫(DLL)中被new,卻在另一個DLL內被delete。許多平臺,這一類“跨DLL的new/delete”會導致運行錯誤,shared_ptr則能解決這個問題
19.設計class猶如設計type
新type的對象應該如何被創建和銷燬(涉及構造和析構函數)
對象初始化和對象賦值應該有什麼差別(涉及構造和assignment)
新type的對象如果被passed by value,意味着什麼?(複製構造)
什麼是新type的“合法值”(注意錯誤檢查,拋出異常)
新type是否需要配合某些繼承圖系(涉及virtual)
新type需要什麼樣的轉換(涉及隱式轉換與否,構造函數是否explicit)
什麼樣的操作符和函數對新type合理(需要聲明什麼成員函數)
什麼樣的標準函數應該駁回(那些需要聲明爲private)
誰該用新type的成員(確定public、private、protected函數)
什麼是新type未聲明的接口
新type有多麼一般化(定義類,函數模板類)
是否真的需要設計type
20.寧以pass-by-reference-to-const替換pass-by-value
儘量以pass-by-reference-to-const替換pass-by-value。前者通常比較高效,並可避免切割問題
以上規則並不適用於內置類型,以及STL的迭代器和函數對象。對它們而言,pass-by-value往往比較適當
- by-reference主要是避免複製構造,同時,const能夠提示用戶保證不修改輸入
- 切割問題:函數的參數是一個基類,那麼函數內調用的虛函數只能對應基類。當用戶使用的時候,調用該函數,輸入的派生類會被默認“轉爲”基類。by-reference可能保證這種情況下,仍然調用派生類的虛函數- 因爲virtual的函數導致class存在虛函數表,增大了存儲空間
- pass-by-value在內置類型和STL中效果比references好,是因爲它們小,而且編譯器有優化。用戶自定義的類型,即使小,也應該儘量用by-reference-to-const的形式
21.必須返回對象時,別妄想返回其reference
絕不要返回pointer或reference指向一個local stack對象,或返回reference指向一個heap-allocated對象,或返回pointer或reference指向一個local static對象而有可能同時需要多個這樣的對象
一個“必須返回新對象”的函數的正確寫法是讓它返回新對象,儘管表面上似乎違背條款3
- 指向local stack對象,因爲在返回時自動銷燬,指向了奇怪的地方
- 指向heap-allocated對象,有可能會忘記銷燬或者導致無法銷燬
- 指向local static對象,會對多線程安全性出現問題