當乙個物件確實被需要的時候才建立它。
物件的建立(或銷毀)觸發對父物件和成員物件的遞迴建立(銷毀)。要當心複雜層次中物件的復合使用。它們使得建立和銷毀的開銷更為高昂。
初始化成員變數使用顯式構造。
class
ftest
private
: std::wstring _str;
};
只能在執行期間解析的虛函式是不允許使用內聯的。因為函式呼叫的動態繫結是繼承的結果。所以消除動態繫結的一種方法是使用基於模板的設計來替代繼承。模板把解析的步驟從執行期間提前到了編譯期間
預備類
class
locker
virtual
~locker()
virtual
void
lock()
=0;virtual
void
unlock()
=0;}
;class
cirticalsectionlocker
:public locker
~cirticalsectionlocker()
virtual
void
lock
()override
virtual
void
unlock
()override }
;class
mutexlocker
:public locker
~mutexlocker()
virtual
void
lock
()override
virtual
void
unlock
()override }
;class
semaphorelocker
:public locker
~semaphorelocker()
virtual
void
lock
()override
virtual
void
unlock
()override }
;
在派生自string類的基礎上,以如下三個角度來設計
示例**,只是輔助理解,不一定能夠編譯通過
硬編碼
從string類中派生出 criticalsectionstring,mutexstring和semahorestrintg。每個類實現各自的同步機制。
class
mutexstring
:public std::string
private
:mutexlocker _mutexlocker;
}
此種設計在效能上具有優勢。通過虛函式來呼叫正確的lock以及unlock方法。但是此設計的不足之處在於需要為每種同步機制編寫各自的string類。導致**重用性較低
繼承
派生出乙個單獨的threadsafestring類。它包含指向locker物件的指標,在執行期間通過多型機制選擇特定的同步機制。
class
threadsafestring
:public string
intgetlength()
private
: locker* _locker;
}
虛函式呼叫lock以及unlock僅在執行期間解析,因此不能對它們內聯。從而帶來了效能的損失。
模板
基於模板的string類,該類由locker型別引數化後得到
template
<
class
locker
>
class
threadsafestring
:public string
intgetlength()
;private
: locker _locker;};
template
<
class
locker
>
inline
int threadsafestring
::getlength()
這種設計也避免了對lock以及unlock的虛函式呼叫。threadsafestring宣告在例項化模板時選擇特定的同步型別。如同硬編碼一樣,它使編譯器可以解析這兩個虛函式呼叫並且內聯。
模板計算從執行期間提前到編譯期間來做,並且在編譯時使用內聯,因此提高了效能。
如果必須按照值返回物件,通過rvo可以省略建立和銷毀區域性物件的步驟,從而改善效能
class
test
~test()
};void
functionpassvalue
(test test)
//此種方式 編譯器將建立乙個test型別的臨時物件。並且使用test作為輸入引數來複製構造它(臨時物件)。然後臨時物件作為實參傳遞給functionpassvalue 該新建立的臨時物件將按引用方式傳遞給functionpassvalue
void
functionpassreferences
(test &test)
void
functionpasspointer
(test *test)
//按照指標以及引用方式不會產生臨時物件。
建立和銷毀臨時物件的代價是比較高的。倘若可以,應該按指標或者引用來傳遞物件以避免生成臨時物件
如果編寫的函式是按值返回物件(與引用或者指標相對),就很可能產生臨時物件。
std::wstring getwstringbyreturnvalue()
//編譯器生成乙個臨時物件來儲存返回值
關於 std::string的 + 運算子
std::string s1 =
"hello"
;std::string s2 =
"world"
;std::string s3;
s3 = s1 + s2;
//產生乙個臨時物件
std::string s3 = s1+s2;
//不會產生臨時物件
為什麼產生臨時物件
因為我們沒有權利修改s3的舊內容並使用 s1+s2的新內容來覆蓋它。賦值運算
符(=)負責把 s3 由舊內容變為新內容。然而編譯器不允許跳過std::string::operator=(),因此必須生成臨時物件。但如果s3是沒有舊內容的新物件呢?在這種情況下,就無須擔心舊內容。此時編譯器可以使用s3而不是臨時物件來儲存。s1+s2的結果直接複製構造至s3物件中。s3取代了不再必須的臨時物件
臨時物件會以建構函式和析構函式的形式降低一半的效能。
將建構函式宣告為 explicit ,可以組織編譯器在幕後使用型別轉換
編譯器常常建立臨時物件來解決型別不匹配問題。通過函式過載可以避免這種情況
如果可能, 應該盡量避免使用物件拷貝(函式返回按值返回,函式實參為值傳遞)。按引用傳遞和返回物件
在 operator 可能是 "+、-、*「或者」/"的地方。使用 operator=運算子可以消除臨時物件
固定大小
分配固定大小記憶體的記憶體管理器
可變大小
分配任意大小記憶體塊的記憶體管理器。所請求分配的大小事是未知的。
單執行緒
記憶體管理器侷限在乙個單執行緒內。記憶體被乙個執行緒使用,並且不越出該執行緒的界限。這種記憶體管理器不設涉及相互訪問的多執行緒。
多執行緒
記憶體管理器被多個執行緒併發地使用。這種實現需要包含互斥執行的**段。無論什麼時候,只能有乙個執行緒在執行乙個**段。
C 效能的程式設計技術
一 影響 c 效能的基本原理 1.i o 的開銷是最昂貴的 2.函式呼叫的開銷是乙個因素,因此我們應該內聯短小,頻繁呼叫的函式 3.複製物件的開銷是昂貴的。最好選擇按引用傳遞,而不是值傳遞。4.最好採用棧內建立物件,而不是採用堆建立物件 一般在堆內建立物件是在棧內建立物件花費的時間是 20備左右。5...
C 模板元程式設計技術
模板元程式設計 template metaprogramming 更準確的含義應該是 編 可以程式設計序的 程式 而模板元程式 template metaprogram 則是 可以程式設計序的 程式 也就是說,我們給出 的產生規則,編譯器在編譯期解釋這些規則並生成新 來實現我們預期的功能。讓我們來看...
c 程式設計技術之 初衷
從開始接觸計算機這個行業,到現在已經接近十年了,最大的感觸就是 自己費盡心思得到的結論,由於專案進度的原因,總不能很好的總結,當再次用到的時候,發現忘個差不多了。雖然基本思想還是清楚的,但是思想到應用還是有一段距離的 在這個行業,時間就是金錢,工作其實蠻簡單的,無非就是迴圈和判斷。但前提是你要徹底理...