深入探索C 物件模型 之 執行期語意學

2021-03-31 08:56:59 字數 4255 閱讀 4857

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 ...