在
c++
中的一件很困難的事,就是不太容易從程式**看出表示式的複雜度。
如下面語句:
if ( yy.operator = = ( xx.getvalue () ) ) )
將被擴充套件為下面這樣的
c++偽碼:
物件的構造和解構
建構函式一般在物件被構造後呼叫,而析構函式必須被放在每乙個離開點(當時
object
還存活)隻前呼叫。一般而言我們會把
object
盡可能放置在使用它的那個程式區段附近,這樣做可以節省不必要的物件產生操作和摧毀操作。
全域性物件
c++
保證,一定會在
main()
函式中第一次用到
global
變數之前,把
global
變數構造出來,而在
main()
函式結束之前把
global
變數摧毀掉。乙個
global object
如果有constructor
和destructor
的話,我們說它需要靜態的初始化操作和記憶體釋放操作。
被靜態初始化的
object
有一些缺點: 1.
如果exception handling
被支援,那些
objects
將不能夠被放置於
try
區段之內。 2.
為了控制「需要跨越模組做靜態初始化」
objects
的相依順序而扯出來的複雜度。
所以建議不要用那些需要靜態初始化的
global objects。
區域性靜態物件 它的
constructor
和destructor
必須只能施行一次,雖然上述函式可能會被呼叫多次。
只有當含有
local static objects
的函式被呼叫時才會把
local static objects
構造出來。
它們的
destructors
順序也和
constructors
的呼叫順序相反。
物件陣列
vec_new()
和vec_delete()
函式將被呼叫來逐一呼叫陣列裡每個物件的
constructor
和destructor。
如:point knots [ 10 ];
會呼叫:
vec_new ( &knots, sizeof ( point ), 10, &point::point, 0 );
new
和delete
運算子
如:int *pi = new int ( 5 );
實際上是分兩步執行:
int *pi;
if ( pi = _new ( sizeof ( int ) ) )
*pi = 5; 以
constructor
來配置乙個
class object
,情況類似:
point3d *origin = new poit3d;
變成:
point3d *origin;
if ( origin = _new ( sizeof ( point3d ) ) )
origin = point3d::point3d ( origin );
如果實現出
exception handling
,那麼轉換結果可能會更複雜些:
if ( origin = _new ( sizeof ( point3d ) ) )
catch(…) }
}
destructor
的應用極為類似:
delete origin;
會變成:
if ( origin != 0 )
一般的
library
對於new
運算子的實現操作有兩個精巧之處:
extern void* operator new ( size_t size )
return last_alloc; }
針對陣列的
new 語意
如:int *p_array = new int [ 5 ];
變成:
int *p_array = ( int* ) _new ( 5 * sizeof ( int ) );
再如有
constructor
函式的物件陣列的
new
語意:
point3d *p_array = new point3d [10 ];
變成:
point3d *p_array;
p_array = vec_new ( 0, sizeof ( point3d ), 10, &point3d::point3d, &point3d::~point3d );
最好避免以乙個
base class
指標指向乙個
derived class objects
所組成的陣列——如果
derived class object
比其base
大的話。因為在
delete
的時候不會呼叫
derived class
的destructor
函式。如過非得那樣寫,就把
base class
指標強制轉換成
derived class
指標在delete。
placement operator new
的語意
point2w *ptw = new ( arena ) point2w;
實際**是:
point2w *ptw = ( point2w* ) arena;
if ( ptw != 0 )
ptw->point2w::point2w ();
當你想用
placement operator
在原已存在的乙個
object
上構造新的
object
,而該現有的
object
有一destructor
,那麼應該用
placement operator delete
來呼叫它的
destructor。
c++說
arena
必須指向相同型別的
class
,要不就是一快「新鮮」記憶體,足夠容納該型別的
object
。但是,
derived class
很明顯不在被支援之列。對於乙個
derived class
,或是其他沒有關聯的型別,其行為雖然並非不合法,卻也未經定義。
「新鮮」的儲存空間可以這樣配置而來:
char *arena = new char [ sizeof ( point2w ) ];
相同型別的
object
則可以這樣獲得;
point2w *arena = new point2w;
placement new operator
並不支援多型。被交給
new
的指標,應該適當地指向一快預先配置好的記憶體。
臨時性物件
在某些環境下,由
processor
產生臨時性物件是有必要的,亦或是比較方便的。這樣的臨時性物件由編譯器來定義。
初始化操作:
t c = a + b;//
將不產生臨時物件
總比下面的操作更有效率地被編譯器轉換:
c = a + b;//
會產生臨時物件
a + b;//
也會產生臨時物件
臨時性物件的被摧毀,應該是對完整表示式求值過程中的最後乙個步驟。該完整表示式造成臨時物件的產生。
。。。。。。凡含有表示式執行結果的臨時性物件,應該存留到
object
的初始化操作完成為止。
如果乙個臨時性物件被繫結於乙個
reference
,物件將殘留,直到被初始化之
reference
的生命結束,或直到臨時物件的生命範疇結束——視哪一種情況先到達而定。
深入探索C 物件模型之六 執行期語意學
c 最困難的一點就在於 無法從程式原始碼看出程式表示式的複雜度。因為編譯器會在背後給你做很多的工作。對於一些表示式諸如t a b c,編譯器可能會建立在執行期過程建立臨時物件,那麼在程式的出口處編譯器就需要安插必要的 來保證建立的臨時物件都得到有效的析構。如果遇到goto switch等會產生多個邏...
深入c 物件模型之執行期語意學
1.物件的構造與解構 一般而言,constructor 和 destructor的安插都會如你所預期 c 偽碼 point point 一般而言會被安插在這裡 一般而言會被安插在這裡 注意 一般而言我們會將物件放置在使用它的程式附近,這樣做可以節省不必要的物件產生操作和摧毀操作。1 全域性物件 c ...
《深度探索C 物件模型》第六章 執行期語意學
new運算子和delete運算子 運算子new看似是乙個簡單的運算,比如 int pi new int 5 但是它實際由兩個步驟完成 1.通過適當的new運算子函式實體,配置所需的記憶體 呼叫函式庫中的new運算子 int pi new sizeof int 2.給配置得到的物件分配初值 pi 5 ...