[深度探索C++物件模型](簡體版)中的蛇足

來源:互聯網
上載者:User

 

<深度探索C++物件模型>>(簡體版)中的蛇足

(沒有此書的人請勿看)

上次見到這本書是一年前(是候先生的繁體版),花了一個星期的時間讀完,囫圇吞棗,不求甚解,饒是如此,也解決了我在C++方面的諸多疑惑,這次終於看到了簡體版,同樣花了一個星期,或許真的是一回生,兩回熟吧(也可能是對簡體文字的親切感^_^),思考問題的同時也發現了一些問題,一愚之見,不吐不快。

蛇足之一,P84,

class X {};

class Y : public virtual X {};

class Z : public virtual Z {};

class A : public X, pubic Z {};

書中寫到

事實上這個大小受到3個因素的影響,

1)      語言本身所造成的額外負擔,。

2)      編譯器對於特殊情況所提拱的最佳化處理。。

3)      Alignment的限制。。

候先生自己添加的如下:

 

當時看這個圖真是“百思不得其解”,無論對於Y或Z來說,既然已經從X virtual繼承,也就有了的額外的4byte開銷,也就是說已經不是一個empty class,那個1 char byte for Y(Z) is empty也就說不通了,而且從lippman的本意來看,

              “2)編譯器對於特殊情況所提供的最佳化處理,virtual base class X的1byte subobject也出現在class Y和Z身上,傳統上它被放在derived class的固定(不變動)部分的尾端”,P88中說明,“它把資料直接存放於每一個class object之中,對於繼承而來的nonstatic data member(不管是virtual或nonvirtual base class)均是如此”,

因此,我理解的圖應該是這樣的:

 

也就是說,父類中成員是直接繼承到子類中的,只不過對於虛擬繼承來說,需要通過一個間接層(表現為某種形式的指標)來存取,這一想法在3.5節(虛擬繼承)中再次得到驗證,(見P121),書中還提到,empty base class的最佳化通常把empty base class置於derived class object開頭一部分,從而不花費任何額外空間。由此也可以分析出,A的結構如下:(本書中,候先生沒有給出這張圖)

sizeof(A)為12個byte,在empty base class最佳化的情況下,為8個Byte。

蛇足之二,P234,

候先生改動了lippman的順序(指析構時發生的事情),他的根據是“這樣才符合ctor的相反順序”,這也未免太主觀了一點,過於咬文嚼字了吧,君不見lippman說“2,dtor的函數本身現在被執行,也就是說vptr會在程式員的碼執行之前被重設”,事實上。

struct b {};

struct d1 : virtual public b {};

struct d2 : virtual public b {};

struct d : public d1, d2 {};

Ctor如下: (可參考Vertex3d的ctor)

d()
{
if( __most_derived )
    this->b();

this->d1(false), this->d2(false);

vptr = d::vptr;
// usercode
}

file://編譯器擴充dtor如下,按相反順序。
~d()
{
vptr = d::vptr;    //**//
//user code...

this->~d2(false), this~d1(false);
if( __most_derived )
    this->~b();

}

這不就是lippman的意思嗎(見書上從1到5的順序)?候先生所謂的相反自訂的順序反而難以理解。

當d被析構的時候,先設vptr = d::vptr,再執行解構函式體,然後依次設d2::vptr, d1::vptr, 最後b::vptr,這些都很容易明白。

而候先生第3點表明“如果object內帶一個vptr,則現在被重新設定,指向適當之base class的virtual table”,即認為vptr的設定為跳躍式的,是在~d()中user code 執行完之後(//**//標記的那行不執行),設定vptr 為d2::vptr,然後執行~d2()函數體,最後在~d2()的末尾設定vptr為d1::vptr,再執行~d1(),奇哉!

這可是一個類設定vptr為另一個不相關的類的vptr啊,它們之間可是沒有母子關係的噢。個人覺得候先生所制定的順序過於理論化了,而lippman的方法是從實際出發的。

蛇足之三:P263

class Point

{

public:

       virtual ~Point() {}

};

 

class Point3d : public Point

{

};

 

Point *ptr = new Point3d[10];

for( int ix = 0 ; ix < elem_count ; ++ix )

{

       Point *p = &((Point3d*)ptr)[ix];

       delete p;

}

候先生將之改為:

for( int ix = 0 ; ix < elem_count ; ++ix )

{

       Point3d *p = &((Point3d*)ptr)[ix];

       delete p;

}

這一處很明顯,虛擬解構函式用不著指定明顯類型,就算指定了類型,都是被resolve成(p->vptr[1])(p),不會帶來效能上的改善。

最後指出一點,lippman認為

Point *ptr = new Point3d[10];

delete[] ptr;

“這樣做完全不是個好主意(具體解釋見P263)”,或許在他那個時候不是吧^_^,但就我在VC6上的測試結果,是完全正確的,所以大家還是可以放心的這樣用,(我沒有測試其它編譯器,有興趣的可以自己試試)。

佳節之日,倉促成文,恐詞不答意,請見諒。
                                                                    19時16分2001/10/1

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.