/********************************************\
|????歡迎轉載, 但請保留作者姓名和原文鏈接, 祝您進步并共勉!???? |
\********************************************/
C++對象模型(6) -? Program Transformation Semantics
作者: Jerry Cat
時間: 2006/05/11
鏈接:?
http://www.shnenglu.com/jerysun0818/archive/2006/05/11/6912.html
2.3 Program Transformation Semantics
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
1). Explicit Initialization:
Given the definition
X x0;
the following three definitions each explicitly initialize its class object with x0:
void foo_bar() {
?? X x1( x0 );
?? X x2 = x0;
?? X x3 = x( x0 );
?? // ...
}
The required program transformation is two-fold:
Each definition is rewritten with the initialization stripped out.
An invocation of the class copy constructor is inserted.
For example, foo_bar() might look as follows after this straightforward, two-fold transformation:
// Possible program transformation Pseudo C++ Code
void foo_bar() {
?? X x1;
?? X x2;
?? X x3;
?? // compiler inserted invocations of copy constructor for X
?? x1.X::X( x0 );
?? x2.X::X( x0 );
?? x3.X::X( x0 );
?? // ...
}
where the call
x1.X::X( x0 );
represents a call of the copy constructor
X::X( const X& xx );
2). Argument Initialization盡量不用傳值法, 要穿指針或引用. 傳值法開銷大效率低,
??? 更要命的是涉及到深淺拷貝以及, 局部變量和臨時對象的銷毀問題.
3). Return Value Initialization(雙重變形, Bjarne Stroutstrup的trick):
(按: 返回值(不是引用或指針,返回的是value), 其實是讓一外部對象的引用做一個"悄然追加"
???? 的參數(編譯器偷著干的, 你是看不見的:), 然后是空返回, 你的返回值呢? 諾, 就是那
???? 以"外追"方式進入函數內部參與處理的引用呵^_^ )
Given the following definition of bar():
X bar()
{
?? X xx;
?? // process xx ...
?? return xx;
}
you may ask how might bar()'s return value be copy constructed from its local object xx?
Stroustrup's solution in cfront is a two-fold transformation:
Add an additional argument of type reference to the class object. This argument will hold the
copy constructed "return value."
Insert an invocation of the copy constructor prior to the return statement to initialize the
added argument with the value of the object being returned.
What about the actual return value, then? A final transformation rewrites the function to have
it not return a value. The transformation of bar(), following this algorithm, looks like this:
// function transformation to reflect application of copy constructor Pseudo C++ Code
void bar( X& __result )
{
?? X xx;
?? // compiler generated invocation of default constructor
?? xx.X::X();
?? // ... process xx
?? // compiler generated invocation of copy constructor
?? __result.X::X( xx );
?? return;
}
Given this transformation of bar(), the compiler is now required to transform each invocation
of bar() to reflect its new definition. For example,
X xx = bar();
is transformed into the following two statements:
// note: no default constructor applied
X xx;
bar( xx );
while an invocation such as
bar().memfunc();
might be transformed into
// compiler generated temporary
X __temp0;
( bar( __temp0 ), __temp0 ).memfunc();
Similarly, if the program were to declare a pointer to a function, such as
X ( *pf )();
pf = bar;
that declaration, too, would need to be transformed:
void ( *pf )( X& );
pf = bar;
4). Optimization at the Compiler Level:
In a function such as bar(), where all return statements return the same named value, it is
possible for the compiler itself to optimize the function by substituting the result argument
for the named return value. For example, given the original definition of bar():
X bar()
{
?? X xx;
?? // ... process xx
?? return xx;
}
__result is substituted for xx by the compiler:
void
bar( X &__result )
{
?? // default constructor invocation Pseudo C++ Code
?? __result.X::X();
?? // ... process in __result directly
?? return;
}
This compiler optimization, sometimes referred to as the Named Return Value (NRV) optimization.
Although the following three initializations are semantically equivalent:
X xx0( 1024 );
X xx1 = X( 1024 );
X xx2 = ( X ) 1024;
in the second and third instances, the syntax explicitly provides for a two-step initialization:
Initialize a temporary object with 1024.
Copy construct the explicit object with the temporary object.
That is, whereas xx0 is initialized by a single constructor invocation
// Pseudo C++ Code
xx0.X::X( 1024 );
a strict implementation of either xx1 or xx2 results in two constructor invocations, a temporary
object, and a call to the destructor of class X on that temporary object:
// Pseudo C++ Code
X __temp0;
__temp0.X::X( 1024 );
xx1.X::X( __temp0 );
__temp0.X::~X();
5). The Copy Constructor: To Have or To Have Not?
??? =============================================
Given the following straightforward 3D point class:
class Point3d {
public:
?? Point3d( float x, float y, float z );
?? // ...
private:
?? float _x, _y, _z;
};
should the class designer provide an explicit copy constructor?
The default copy constructor is considered trivial. There are no member or base class objects
with a copy constructor that need to be invoked. Nor is there a virtual base class or virtual
function associated with the class. So, by default, a memberwise initialization of one Point3d
class object with another results in a bitwise copy. This is efficient. But is it safe?
The answer is yes. The three coordinate members are stored by value. Bitwise copy results in
neither a memory leak nor address aliasing. Thus it is both safe and efficient.
So, how would you answer the question, should the class designer provide an explicit copy
constructor? The obvious answer, of course, is no. There is no reason to provide an instance
of the copy constructor, as the compiler automatically does the best job for you. The more subtle
answer is to ask whether you envision the class's requiring a good deal of memberwise
initialization, in particular, returning objects by value? If the answer is yes, then it makes
excellent sense to provide an explicit inline instance of the copy constructor that is, provided
your compiler provides the NRV optimization(虛擬語氣).
For example, the Point3d class supports the following set of functions:
Point3d operator+( const Point3d&, const Point3d& );
Point3d operator-( const Point3d&, const Point3d& );
Point3d operator*( const Point3d&, int );
etc.
all of which fit nicely into the NRV template
{
?? Point3d result;
?? // compute result
?? return result
}
The simplest method of implementing the copy constructor is as follows:
Point3d::Point3d( const Point3d &rhs )
{
?? _x = rhs._x;
?? _y = rhs._y;
?? _z = rhs._z;
};
This is okay, but use of the C library memcpy() function would be more efficient:
Point3d::Point3d( const Point3d &rhs )
{
?? memcpy( this, &rhs, sizeof( Point3d );
};
Use of both memcpy() and memset(), however, works only if the classes do not contain any
compiler-generated internal members. If the Point3d class declares one or more virtual functions
or contains a virtual base class, use of either of these functions will result in overwriting the
values the compiler set for these members. For example, given the following declaration:
class Shape {
public:
?? // oops: this will overwrite internal vptr!
?? Shape() { memset( this, 0, sizeof( Shape ));
?? virtual ~Shape();
?? // ...
};
the compiler augmentation for the constructor generally looks like this:
// Expansion of constructor Pseudo C++ Code
Shape::Shape()
{
?? // vptr must be set before user code executes
?? __vptr__Shape = __vtbl__Shape;
?? // oops: memset zeros out value of vptr
?? memset( this, 0, sizeof( Shape ));
};
As you can see, correct use of the memset() and memcpy() functions requires some knowledge of the
C++ Object Model semantics! 嘿, 把C庫扯進來了, 強! C庫中許多強調性能,效率的函數是用匯編寫的
Summary: 編譯器盡可能地"優化掉"拷貝構造函數, 代之以NRV...
---------------------------------------------------------
Application of the copy constructor requires the compiler to more or less transform portions of
your program. In particular, consider a function that returns a class object by value for a class
in which a copy constructor is either explicitly defined or synthesized. The result is profound
program transformations both in the definition and use of the function. Also, the compiler
optimizes away the copy constructor invocation where possible, replacing the NRV with an additional
first argument within which the value is stored directly. Programmers who understand these
transformations and the likely conditions for copy constructor optimization can better control the
runtime performance of their programs.
posted @
2006-05-11 03:33 Jerry Cat 閱讀(586) |
評論 (0) |
編輯 收藏
檢測文件存在的三種方法 - test if a File exist or not?
1. 強大, 可配合FindNextFile(), FindClose(), 其中后者是必備.
WIN32_FIND_DATA m_data;
HANDLE hFile;
hFile=FindFirstFile(filename,&m_data)
if(hFile==INVALID_HANDLE_VALUE) //file not found
Make sure you close the handle if the file is found.
FindClose(hFile);
2. You can use SHGetFileInfo()
The prototype of the function is as follows:
DWORD_PTR SHGetFileInfo(
LPCTSTR pszPath,
DWORD dwFileAttributes,
SHFILEINFO *psfi,
UINT cbFileInfo,
UINT uFlags
);
備注:
Minimum DLL Version shell32.dll version 4.0 or later
Header? shellapi.h
Import? library shell32.lib (若是ClassWizard建的無論是SDK還是MFC都會自包括)
Minimum operating systems Windows NT 4.0, Windows 95
Unicode Implemented as ANSI and Unicode versions.?
3. 簡潔的 PathFileExists()
BOOL PathFileExists(
??? LPCTSTR lpszPath
??? );
Purpose: Determines if a file exists.
Remark:? #include "Shlwapi.h"
Minimum DLL Version shlwapi.dll version 4.71 or later
Header? shlwapi.h
Import? library shlwapi.lib
Minimum operating systems Windows 2000, Windows NT 4.0 with Internet Explorer 4.0, Windows 98, Windows 95 with Internet Explorer 4.0
Unicode Implemented as ANSI and Unicode versions.
posted @
2006-05-11 00:53 Jerry Cat 閱讀(1469) |
評論 (0) |
編輯 收藏
C++ virtual member function FAQ
【1】? 虛成員函數和非虛成員函數調用方式有什么不同?
??? 非虛成員函數是靜態確定的。也就是說,該成員函數(在編譯時)被靜態地選擇,該選擇基于指向對象的指針(或引用)的類型。 相比而言,虛成員函數是動態確定的(在運行時)。也就是說,成員函數(在運行時)被動態地選擇,該選擇基于對象的類型,而不是指向該對象的指針/引用的類型。這被稱作“動態綁定/動態聯編”。大多數的編譯器使用以下的一些的技術,也就是所謂的“VTABLE”機制:
???? 編譯器發現一個類中有被聲明為virtual的函數,就會為其搞一個虛函數表,也就是VTABLE。VTABLE實際上是一個函數指針的數組,每個虛函數占用這個數組的一個slot。一個類只有一個VTABLE,不管它有多少個實例。派生類有自己的VTABLE,但是派生類的VTABLE與基類的VTABLE有相同的函數排列順序,同名的虛函數被放在兩個數組的相同位置上。在創建類實例的時候,編譯器還會在每個實例的內存布局中增加一個vfptr字段,該字段指向本類的VTABLE。通過這些手段,編譯器在看到一個虛函數調用的時候,就會將這個調用改寫,在分發一個虛函數時,運行時系統跟隨對象的 v-pointer找到類的 v-table,然后跟隨v-table中適當的項找到方法的代碼。
??? 以上技術的空間開銷是存在的:每個對象一個額外的指針(僅僅對于需要動態綁定的對象),加上每個方法一個額外的指針(僅僅對于虛方法)。時間開銷也是有的:和普通函數調用比較,虛函數調用需要兩個額外的步驟(得到v-pointer的值,得到方法的地址)。由于編譯器在編譯時就通過指針類型解決了非虛函數的調用,所以這些開銷不會發生在非虛函數上。
【2】 析構函數也可以是虛的,甚至是純虛的,但是構造函數不能是虛的
???? 純虛的析構函數并沒有什么作用,是虛的就夠了。通常只有在希望將一個類變成抽象類(不能實例化的類),而這個類又沒有合適的函數可以被純虛化的時候,可以使用純虛的析構函數來達到目的。構造函數不能是虛的(為什么?因為在一個構造函數調用期間,虛機制并不工作),但是你可以可能通過虛函數 virtual clone()(對于拷貝構造函數)或虛函數 virtual create()(對于默認構造函數),得到虛構造函數產生的效果。如下:
class Shape {
?public:
?? virtual ~Shape() { }???????????????? // 虛析構函數
?? virtual void draw() = 0;???????????? // 純虛函數
?? virtual void move() = 0;
?? // ...
?? virtual Shape* clone()? const = 0;?? // 使用拷貝構造函數
?? virtual Shape* create() const = 0;?? // 使用默認構造函數
?};
?
?class Circle : public Shape {
?public:
?? Circle* clone()? const { return new Circle(*this); }
?? Circle* create() const { return new Circle();????? }
?? // ...
?};
??? 在 clone() 成員函數中,代碼 new Circle(*this) 調用 Circle 的拷貝構造函數來復制this的狀態到新創建的Circle對象。在 create()成員函數中,代碼 new Circle() 調用Circle的默認構造函數。
用戶將它們看作“虛構造函數”來使用它們:
?void userCode(Shape& s)
?{
?? Shape* s2 = s.clone();
?? Shape* s3 = s.create();
?? // ...
?? delete s2;??? // 在此處,你可能需要虛析構函數
?? delete s3;
?}
??? 這個函數將正確工作,而不管 Shape 是一個Circle,Square,或是其他種類的 Shape,甚至它們還并不存在。
【3】 構造函數和析構函數中的虛函數調用
??? 一個類的虛函數在它自己的構造函數和析構函數中被調用的時候,它們就變成普通函數了,不“虛”了。也就是說不能在構造函數和析構函數中讓自己“多態”。例如:
class A
{
public:
??? A() { foo();}??????? // 在這里,無論如何都是A::foo()被調用!
??? ~A() { foo();}?????? // 同上
??? virtual void foo();
};
class B: public A
{
public:
??? virtual void foo();
};
void bar()
{
??? A * a = new B;
??? delete a;
}
??? 如果你希望delete a的時候,會導致B::foo()被調用,那么你就錯了。同樣,在new B的時候,A的構造函數被調用,但是在A的構造函數中,被調用的是A::foo()而不是B::foo()。為什么會有這樣的規定呢,原因如下:
??? 當基類被構造時,對象還不是一個派生類的對象,所以如果 Base::Base()調用了虛函數 virt(),則 Base::virt() 將被調用,即使 Derived::virt()(派生類重寫該虛函數)存在。
??? 同樣,當基類被析構時,對象已經不再是一個派生類對象了,所以如果 Base::~Base()調用了virt(),則 Base::virt()得到控制權,而不是重寫的 Derived::virt() 。
??? 當你可以想象到如果 Derived::virt() 涉及到派生類的某個成員對象將造成的災難的時候,你很快就能看到這種方法的明智。詳細來說,如果 Base::Base()調用了虛函數 virt(),這個規則使得 Base::virt()被調用。如果不按照這個規則,Derived::virt()將在派生對象的派生部分被構造之前被調用,此時屬于派生對象的派生部分的某個成員對象還沒有被構造,而 Derived::virt()卻能夠訪問它。這將是災難。
【4】私有private的虛函數是否具有多態性?
??? 考慮下面的例子:
class A
{
public:
??? void foo() { bar();}
private:
??? virtual void bar() { ...}
};
class B: public A
{
private:
??? virtual void bar() { ...}
};
??? 在這個例子中,雖然bar()在A類中是private的,但是仍然可以出現在派生類中,并仍然可以與public或者protected的虛函數一樣產生多態的效果。并不會因為它是private的,就發生A::foo()不能訪問B::bar()的情況,也不會發生B::bar()對A::bar()的override不起作用的情況。
??? 這種寫法的語意是:A告訴B,你最好override我的bar()函數,但是你不要管它如何使用,也不要自己調用這個函數。
posted @
2006-05-10 23:47 Jerry Cat 閱讀(520) |
評論 (0) |
編輯 收藏
2006德國世界杯主題曲 Time of Our Lives(生命之巔)
? ?
描述:即將舉行的2006德國世界杯的主題曲2月9日最終確定,由SonyBMG唱片公司著名作曲家約爾根·埃洛弗松(Jorgen Elofsson)作曲,超級制作人史蒂夫·麥克(Steve Mac)制作的“生命之巔”(Time of Our Lives)最終成為2006德國世界杯的官方主題曲。
據加拿大新聞專線網近日的報道,由國際足聯授權的,負責制作2006德國世界杯主題曲的唱片公司SongBMG將邀請曾刷新英美排行記錄、震撼全球唱銷的超人氣組合“美聲男伶”(Il Divo)到現場為球迷傾情演出。
“我們生命中的時光”作為世界杯主題曲將會在6月9日慕尼黑的世界杯開幕式上由“美聲男伶”組合首演。屆時全世界會有超過10億名觀眾通過電視欣賞到這首主題歌。
除了這首主題曲外,一本名為“VOICES”的世界杯歌曲專輯也將于今年5月底面世。這本歌曲專輯將包含了當今很多的暢銷歌曲,除了“美聲男伶”外,像瑪利亞凱利,席琳迪翁,胡利奧伊格萊西亞斯,惠特尼休斯頓等等大牌歌星也將在這本專輯中獻唱。
本屆世界杯還將史無前例地推出第二首主題曲,屆時將由著名的德國男歌手赫爾柏特·格羅內邁耶爾演唱。
世界杯中文版會歌將由實力派唱將庾澄慶主唱,而中文版主題曲則會由Sony BMG旗下的七位歌手(樂團)共同演繹。
歌詞:
Deutschland
德國
Deutsch, deutsch, deutsch, deutsch, deutsch, deutsch
德語,德意志,德國人,……………
Natürlich hat ein Deutscher "Wetten, dass ... ?" erfunden
肯定只有德國人才能說出這樣的話:“我說的是不會錯的,打個賭好嗎?”
Vielen Dank für die schoenen Stunden
非常感謝,我們過的非常愉快!
Wir sind die freundlichsten Kunden auf dieser Welt
我們是這個世界上最好的顧客
Wir sind bescheiden, wir haben Geld
我們謙虛并富有
Die Allerbesten in jedem Sport
我們有最好的運動員
Die Steuern hier sind Weltrekord
德國的捐稅世界聞名
Bereisen Sie Deutschland und bleiben Sie hier
歡迎來德國旅行和逗留
Auf diese Art von Besuchern warten wir
我們期待您的光臨
Es kann jeder hier wohnen, dem es gefaellt
只要高興,誰都可以來德國住住
Wir sind das freundlichste Volk auf dieser Welt
我們是世界上最友善的民族
Deutsch, deutsch, deutsch, deutsch
德語,德意志,德國人,
Nur eine Kleinigkeit ist hier verkehrt
要澄清的一點小誤會是,
Und zwar, dass Schumacher keinen Mercedes faehrt
舒馬赫開的并不是梅塞德斯車
Das alles ist Deutschland
這就是德國
Das alles sind wir
我們就是德國人
Das gibt es nirgendwo anders
這里一點都不怪
Nur hier, nur hier
德國,德國
Das alles ist Deutschland
這就是德國
Das sind alles wir
我們就是德國人
Wir leben und wir sterben hier
我們在這里生活和死亡
Deutsch, deutsch, deutsch, deutsch
德語,德意志,德國人,……………
Deutsch, deutsch, deutsch, deutsch
德語,德意志,德國人,……………
Es bilden sich viele was auf Deutschland ein
都說德國人很自負
Und mancher findet es geil, ein Arschloch zu sein
不少德國人都認為不要臉的家伙就是好色之徒
Es gibt Manchen, der sich gern über Kanacken beschwert
有些人喜歡為了雞毛蒜皮的小事而抱怨
Und zum Ficken jedes Jahr nach Thailand faehrt
有些人為了追求刺激每年都要去泰國
Wir lieben unsere Autos mehr als unsere Frauen
我們愛女人但更愛汽車
Den deutschen Autos koennen wir vertrauen
我們信賴德國車
Gott hat die Erde nur einmal geküsst
上帝偏愛德國,即使在他唯一一次親吻地球時,
Genau an dieser Stelle, wo jetzt Deutschland ist
接受上帝之吻的地方就是現在的德國
Wir sind überall die Besten natürlich auch im Bett
我們什么都要做到最好,當然做愛也不例外
Und zu Hunden und Katzen besonders nett
貓和狗深受我們的喜愛
Das alles ist Deutschland
這就是德國
Das alles sind wir
我們就是德國人
Das gibt es nirgendwo anders
這里一點都不怪
Nur hier, nur hier (zwo, drei, vier)
德國,德國
Das alles ist Deutschland
這就是德國
Das sind alles wir
我們就是德國人
Wir leben und wir sterben hier
我們在這里生活和死亡
Wir sind besonders gut in und auf die Fressehauen
我們是出色的戰士
Auch im Feuerregen kann man uns vertrauen
即使在槍林彈雨中人們也能信任我們
Wir stehen auf Ordnung und Sauberkeit
我們講條里和喜歡整潔
Wir sind jederzeit für'n Krieg bereit
我們枕戈待旦
Schon Gross an die Welt zieht es endlich ein
總有一天大德意志會重現世界
Wir koennen stolz auf Deutschland sein
我們能為德國而驕傲
Schwein, Schwein, Schwein, Schwein
可憐蟲,可憐蟲,可憐蟲,可憐蟲
Schwein, Schwein, Schwein, Schwein
可憐蟲,可憐蟲,可憐蟲,可憐蟲
Das alles ist Deutschland
這就是德國
Das alles sind wir
我們就是德國人
Das gibt es nirgendwo anders
這里一點都不怪
Nur hier, nur hier
德國,德國
Das alles ist Deutschland
這就是德國
Das sind alles wir
我們就是德國人
Wir leben und wir sterben hier
我們在這里生活和死亡
Das alles ist Deutschland
這就是德國
Das alles sind wir
我們就是德國人
Das gibt es nirgendwo anders
這里一點都不怪
Nur hier, nur hier
德國,德國
Das alles ist Deutschland
這就是德國
Das sind alles wir
我們就是德國人
Wir leben und wir sterben hier
我們在這里生活和死亡
posted @
2006-05-08 16:15 Jerry Cat 閱讀(439) |
評論 (1) |
編輯 收藏
泰國驚魂記 - 來點輕松又刺激的, 僅獻給黃金周海外旅行的朋友
泰國驚魂記(一)曼谷被甩
原文見:
http://blog.donews.com/zrde/archive/2006/05/06/857839.aspx
回來了。帶著被熱帶陽光灼傷的皮膚回來了。背后、肩膀、臉曬傷了一大片,一碰火辣辣得痛。
讓我開眼的倒還不完全是普吉島的風光,反倒是旅行的遭遇到真讓我長了見識。用張銳普吉驚魂記做線索吧。說說這幾日的趣事。
一、曼谷被甩
5月1日,做了將近5個小時的飛機來到曼谷國際機場,下了飛機,熱浪滔天。見機場工作人員拿著個“普吉島由此去”的指示牌,連忙逃竄到擺渡車上,心里還得意,多虧兄弟我身手敏捷,擠上了車,否則站在日頭里等車,不被曬成人肉干才怪。
懷著對海島椰林的美麗騷情來到了候機大廳,可越走越覺得不對——同機的團友一個也不見。開始想,或許他們在后頭,沒跟上。過了半晌,依然不見人影。心里發慌,腿腳開始哆嗦,往前找,沒人,往后找,一樣沒人。
突然,看見一對似曾相識的人姍姍走來,這,不就是傳說中的團友嘛!像見了親人一樣的連忙上前,一問才曉得他倆也是和大部隊走散,也在找團隊。四個人聚頭,開始分析、揣測、研究大部隊的走向。遂決定,一路去轉機的大廳尋找戰友,一路往辦理登機手續的柜臺查尋航班號。
法網恢恢,疏而不漏,滿懷希望地開始尋團行動,可一會兒,四個人垂頭喪氣的回來報告壞消息:飛機票在導游身上,泰國人民根本就不讓我們進轉機的大廳,賠上泱泱大國勤勞勇敢的笑臉,才得以讓我們進去瞅了幾眼,可哪里有同伴的影子啊;到柜臺查航班號得來的消息更是絕望,我們從曼谷轉機去普吉的飛機已經起飛了!
美麗騷情沒了,連僥幸的心也沒了,只剩下對缺心眼的導游的深情詛咒——我靠,也太***操蛋了吧,4個大活人的機票還在你手上,你吭都不吭一聲,就屁股冒煙的飛普吉了。這導游不一般,不一般呀不一般!
掐著時間,算我們親愛的導游已經到了普吉島,忍著每分鐘5.8元的國際漫游費,給導游打電話。靜默半晌,傳來“您撥打的電話已關機,請稍后再撥”的天底下最喪門星的聲音。四個人真的是絕望了。曼谷機場的空調不錯,干凈的落地大窗前擺放著熱帶蘭花,四周是異族人五顏六色的面孔和表情,恍恍惚惚真叫人覺得不真實——傳說中的“甩客”居然降臨到兄弟我的頭上!
四個人茫茫然站在大廳里,忽然親近許多。彼時彼刻,兄弟我也真的理解了“同是天涯淪落人,相逢何必曾相識”的蒼茫詩意。百般無奈,向普吉的地接旅行社求救,電話那頭傳來一個中年男人的南方口音,我靠,那一剎,我有了楊立偉在神六太空艙搞“天地對話”時的激動心情。我差點忘掉了我們的悲慘遭遇,我只想對這電話大聲喊:“感謝祖國、感謝黨!”然而,地接社的人也聯系不上導游,只曉得他們已經到了普吉機場。
看來,靠天靠地不如靠自己,我們只有痛定思痛,自己買機票趕往普吉島了。后來的事情不說了。千辛萬苦,外加近13000多泰銖的飛機票,才讓俺們4個人來到美麗的普吉島。下了飛機,兄弟我的心情又酸又辣,如同扯蛋的泰國菜一般。熱帶風情引發的旅游騷情早已蕩然無存,只剩下抽人的沖動。
事后向導游興師問罪,才知道大部隊根本就沒有辦理轉機手續,從北京至曼谷的飛機下來之后,直接被拉到了曼谷至普吉的航班上。導游或者是在飛機上跟我們言語一聲,或者是在我們下飛機的時候叮囑一下,或者是事后開著手機,實在不行就把機票分給我們,也不至于讓我們在曼谷機場度過黑暗的幾小時。丫就能生生的把這順理成章的一切統統拋在腦后,心安理得地飛普吉去了。你說神奇不神奇?
--------------------------
泰國驚魂記(二)人妖亂舞
原文見:
http://blog.donews.com/zrde/archive/2006/05/06/857886.aspx
我實在是想不通,為什么泰國人會對人妖文化很驕傲,這顯然是違反天性的事物啊。我是著實的消受不起,接受不了。
來到普吉島,接站的導游對我們說,你們是先吃飯,還是先看人妖表演。大伙的意思是先看人妖,即便見了也是白見,但畢竟是百聞不如一見。
去就去吧。來到表演場地,人群鼎沸,基本都是來旅游獵奇的大陸同胞。震耳欲聾的音樂響起,五光十色的舞臺亮起,人妖出來了。遠望去,那個姹紫嫣紅啊,身材曼妙,玲瓏有致。但是我一想到他們愿是男兒身,就止不住的有變態之感。
兄弟我有一句流傳頗廣的名言:這是個變態是常態的社會。莫非,莫非,一語成讖,預言成真?忍不住,我跑到外面去抽煙,恍恍惚惚看見路燈下行走的女人,只要是漂亮的、身材好的,我都止不住懷疑她們是不是假貨。看來不能常看人妖表演,意志不堅的,斗志不強的,真的要像我一樣變態了。
( 圖見原文
演出結束,剛走出門,猛聽見身后一陣騷動,原來是尚未協妝的人妖一窩蜂跑出后臺,站在路邊和游客合影,合影一次,索20泰銖(合5元人民幣)的小費。她們(他們?)盡可能地裸露著身體,站在濕熱的風中,招著手、扭著身子、撒嬌扮靚,招呼著游客——像紅燈區生意清淡的妓女。游客多是大陸來的,生性靦腆,大多站在路的另一邊拿著相機啪啪地照像,真正去和她們合影的倒是不多。
( 圖見原文
忽然間,我想我對她們的態度真是可憎。她們不過是用一種娛樂他人、迎合男性審美或者是變態審美的方式謀生罷了。我的厭惡包含著我的歧視,我的歧視暴露了我的偏狹——我解釋到,我心里是尊敬的,只是生理上的惡心罷了——錯了錯了,這其實是更大的歧視,更深的偏狹。
人妖基本上來自于生活境遇悲慘的家庭,2、3歲的時候就被送進人妖學校學習舞蹈、唱歌,他們常年服用雌性激素,使男性生殖器官萎縮,保證女性第二性征得以發育,皮膚變得細膩、光滑。人妖的壽命一般來說都很短。這些都是代價。
------------------------------------
泰國驚魂記(三)一覺回到解放前
原文見:
http://blog.donews.com/zrde/archive/2006/05/07/859207.aspx
2日一早,醒來就聽到隱隱的濤聲,走出酒店大門,穿過一條干凈的馬路,撲面而來是卡龍灣的寂靜海面。早晨海灘上的人少,沙灘很平,沒有腳印,只有昨夜貪玩滯留在沙灘上的藍色海蜇。陽光多情,安寧鋪在海面和沙灘上,也照我。昨日的不愉快,小了很多。
( 圖見原文
當天的旅行安排,港中旅是這樣的介紹的(原文就是繁體):
早餐後去扯前往攀牙灣割喉島翠峰雨林,抵達後乘坐獨木舟漫遊海蝕山林、鐘乳溶洞,奇景之間,除了兩岸不斷的蟲鳴、鳥聲、猿啼之外聽不到任何其他的紛擾的聲音。輕艇滑過神秘的洞穴之間,盡頭豁然開朗竟是一個隱沒在四面高壁中的神秘湖泊……乘車後體驗從林騎象的威風,乘坐牛車的悠哉遊哉,觀割膠的見識,猴子表演的詼諧……
牛比吧,夢幻吧,芳心暗許了吧。實際如何,請看照片。
( 圖見原文:)
這就是“觀割膠的見識”,樹上那條白色的口子就是割膠用的。孤伶伶一顆橡膠樹下,圍著一大群仰著頭,身著脖子的傻鵝,聽導游進行植物學科普。
( 圖見原文:)
這就是“從林騎象的威風”,騎著臭烘烘的大象,趔趄著走過臭水溝,繞一圈,200米,威風完了。
( 圖見原文:)
這就是“乘坐牛車的悠哉遊哉”。一輛車8個傻鵝,頂著似火驕陽,顛得橫七豎八,也是繞著土路轉200米,就牛車體驗完了,就優哉游哉了。
( 圖見原文:)
這就是“割喉島翠峰雨林,抵達後乘坐獨木舟漫遊海蝕山林、鐘乳溶洞,奇景之間,除了兩岸不斷的蟲鳴、鳥聲、猿啼之外聽不到任何其他的紛擾的聲音。輕艇滑過神秘的洞穴之間,盡頭豁然開朗竟是一個隱沒在四面高壁中的神秘湖泊……”所謂的翠峰雨林是200米高遍布雜樹的小山包,獨木舟是塑料的,所謂的海蝕山林的水是綠的,和玉淵潭的4類水質有一拼,所謂的鐘乳奇觀不過區區50米的一山洞。
半天下來,我感覺就是“一覺回到解放前”,傳說中的亞洲四小龍泰國就是這樣啊,傳說的普吉島人間仙境就是這副嘴臉啊。
懷著大失所望的心,被導游牽到“超五星的博士山莊”用餐,飯菜那個難吃,我都懶得說了,環境倒還不錯,綠水青山,遠處有優雅的小亭閣。
( 圖見原文:)
回到車上,眾人開始吵吵行程中沒有安排著名的pp島,貌似忠厚的導游誠懇說,屁屁島是自費項目,包在整體團費里,旅行社得虧本,所以大家要加錢哦。算下了,每人1000多人民幣。娘的,本來5、1黃金周旅行社就哄抬物價,把價格提高到6800多人民幣/每人,把平時6日游的行程縮水為5天,這好,來了普吉,還要自費去屁屁島。這好比是來北京旅游,導游跟你說,對不起啊,旅行社只安排了到北京西站,故宮啊、頤和園啊、長城啊,自費!
算了算了,既然做了旅行社的傻鵝,就不在乎是不是再多挨上一刀。總不能留個屁屁島,將來再花錢重新來一次吧。忍著被強奸的巨痛,顫巍巍交上人民幣,導游說,只能按照1:4.2兌換為泰銖(官價1:4.6),光收屁屁島的自費項目的費用,導游就從中瞇了近10000泰銖的差價,感情泰國的導游還兼職做炒匯啊。牛比,那是相~~當的牛比!
傻鵝們的待屠生涯按下不表,且說2號下午的行程。傻鵝們灌了一嗉子的食料之后,被導游拉到一個寶石商店,先是參觀,后是購物。作為傻鵝團隊的一員,我想,野百合也有春天啊,傻鵝也有智商啊,不買!堅決不買!轉了一小圈,蟄到街上,看普吉島華人區的街景去了。
( 圖見原文:)
這就是商店里假模假式在生產寶石的售貨員們。看邊上的傻鵝,多專心啊!
( 圖見原文:)
路邊的鳳凰花開的倒還不錯,但是遠沒有我在三亞看到的濃烈動情。招貼上的女同學,我估摸著是普吉島的一個議員,有會泰語的同學,給解釋下啊。
( 圖見原文:)
? ? -- 全文完
posted @
2006-05-07 18:44 Jerry Cat 閱讀(223) |
評論 (0) |
編輯 收藏
/********************************************\
|????歡迎轉載, 但請保留作者姓名和原文鏈接, 祝您進步并共勉!???? |
\********************************************/
C++對象模型(5) -? Copy Constructor Construction
作者: Jerry Cat
時間: 2006/05/05
鏈接:?http://www.shnenglu.com/jerysun0818/archive/2006/05/05/6632.html
2.2 Copy Constructor Construction
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
引子:
Say the class designer explicitly defines a copy constructor (a constructor requiring a single
argument of its class type), such as either of the following:
// examples of user defined copy constructors may be multi-argument provided each second
// and subsequent argument is provided with a default value
X::X( const X& x );
Y::Y( const Y& y, int = 0 );
In this case, that constructor is invoked, under most circumstances, in each program instance
where initialization of one class object with another occurs. This may result in the generation
of a temporary class object or the actual transformation of program code (or both).
1). Default Memberwise Initialization(注:對內建成員對象可遞歸用之):
bitwise:按位
memberwise:逐成員
What if the class does not provide an explicit copy constructor? Each class object initialized
with another object of its class is initialized by what is called default memberwise initialization.
Default memberwise initialization copies the value of each built-in or derived data member (such
as a pointer or an array) from the one class object to another. A member class object, however,
is not copied; rather, memberwise initialization is recursively applied. For example, consider
the following class declaration:
class String {
public:
?? // ... no explicit copy constructor
private:
?? char *str;
?? int?? len;
};
The default memberwise initialization of one String object with another, such as
String noun( "book" );
String verb = noun;
is accomplished as if each of its members was individually initialized in turn:
// semantic equivalent of memberwise initialization
verb.str = noun.str;
verb.len = noun.len;
If a String object is declared as a member of another class, such as the following:
class Word {
public:
?? // ...no explicit copy constructor
private:
?? int???? _occurs;
?? String? _word;
};
then the default memberwise initialization of one Word object with another copies the value of
its built-in member _occurs and then recursively applies memberwise initialization to its class
String member object _word.
How is this operation in practice carried out? The original ARM tells us:
??? Conceptually, for a class X [this operation is] implemented by…a copy constructor.
The operative word here is conceptually. The commentary that follows explains:
??? In practice, a good compiler can generate bitwise copies for most class objects since they
??? have bitwise copy semantics….
That is, a copy constructor is not automatically generated by the compiler for each class that
does not explicitly define one. Rather, as the ARM tells us:
?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? 缺省者按需也
??? Default constructors and copy constructors…are generated (by the compiler) where needed.
Needed in this instance means when the class does not exhibit bitwise copy semantics.(此處的
"needed"意味著彼時該類并無按位拷貝之意). The Standard retains the meaning of the ARM, while
formalizing its discussion (my comments are inserted within parentheses) as follows:
??? A class object can be copied in two ways, by initialization (what we are concerned with
??? here)…and by assignment (treated in Chapter 5). Conceptually (my italics), these two
??? operations are implemented by a copy constructor and copy assignment operator.
As with the default constructor, the Standard speakers of an implicitly declared and implicitly
defined copy constructor if the class does not declare one. As before, the Standard distinguishes
between a trivial and nontrivial copy constructor. It is only the nontrivial instance that in
practice is synthesized within the program(實際上只有"并非不重要"的拷貝構造函數才會被合成進程序
中). The criteria for determining whether a copy constructor is trivial is whether the class
exhibits bitwise copy semantics(類只對"不重要"的拷貝構造函數進行按位拷貝). In the next
section, I look at what it means to say that a class exhibits bitwise copy semantics.
2). Bitwise Copy Semantics:
In the following program fragment:
#include "Word.h"
Word noun( "block" );
void foo()
{
?? Word verb = noun;
?? // ...
}
it is clear that verb is initialized with noun. But without looking at the declaration of class
Word, it is not possible to predict the program behavior of that initialization. If the designer
of class Word defines a copy constructor, the initialization of verb invokes it. If, however,
the class is without an explicit copy constructor, the invocation of a compiler-synthesized
instance depends on whether the class exhibits bitwise copy semantics. For example, given the
following declaration of class Word:
// declaration exhibits bitwise copy semantics
class Word {
public:
?? Word( const char* );
?? ~Word() { delete [] str; }
?? // ...
private:
?? int?? cnt;
?? char *str;
};
a default copy constructor need not be synthesized, since the declaration exhibits bitwise copy
semantics, and the initialization of verb need not result in a function call.
However, the following declaration of class Word does not exhibit bitwise copy semantics:
此時的按位拷貝將是致命的, 最好應顯式定義一拷貝構造函數, 用new從堆中另辟內存塊空間.
??? Of course, the program fragment will execute disastrously given this declaration of class
??? Word. (Both the local and global object now address the same character string. Prior to
??? exiting foo(), the destructor is applied to the local object, thus the character string is
??? deleted. The global object now addresses garbage.) The aliasing problem with regard to member
??? str can be solved only by overriding default memberwise initialization with an explicit copy
??? constructor implemented by the designer of the class (or by disallowing copying altogether).
??? This, however, is independent of whether a copy constructor is synthesized by the compiler.
// declaration does not exhibits bitwise copy semantics
class Word {
public:
?? Word( const String& );
?? ~Word();
?? // ...
private:
?? int??? cnt;
?? String str;
};
where String declares an explicit copy constructor:
class String {
public:
?? String( const char * );
?? String( const String& );
?? ~String();
?? // ...
};
In this case, the compiler needs to synthesize a copy constructor in order to invoke the copy
constructor of the member class String object:
// A synthesized copy constructor (Pseudo C++ Code)
inline Word::Word( const Word& wd )
{
?? str.String::String( wd.str );
?? cnt = wd.cnt;
}
It is important to note that in the case of the synthesized copy constructor, the nonclass
members of types such as integers, pointers, and arrays are also copied, as one would expect.
3). Bitwise Copy Semantics Not! (此時)對按位拷貝大聲說不!
When are bitwise copy semantics not exhibited by a class? There are four instances:
(1). When the class contains a member object of a class for which a copy constructor exists
???? (either explicitly declared by the class designer, as in the case of the previous String
???? class, or synthesized by the compiler, as in the case of class Word)
(2). When the class is derived from a base class for which a copy constructor exists (again,
???? either explicitly declared or synthesized)
(3). When the class declares one or more virtual functions
(4). When the class is derived from an inheritance chain in which one or more base classes are virtual
4). Resetting the Virtual Table Pointer:
Recall that two program "augmentations" occur during compilation whenever a class declares one
or more virtual functions.
??? A virtual function table that contains the address of each active virtual function associated
??? with that class (the vtbl) is generated.
??? A pointer to the virtual function table is inserted within each class object (the vptr).
Obviously, things would go terribly wrong if the compiler either failed to initialize or
incorrectly initialized the vptr of each new class object. Hence, once the compiler introduces
a vptr into a class, the affected class no longer exhibits bitwise semantics. Rather, the
implementation now needs to synthesize a copy constructor in order to properly initialize the
vptr. Here's an example.
First, I define a two-class hierarchy of ZooAnimal and Bear:
class ZooAnimal {
public:
?? ZooAnimal();
?? virtual ~ZooAnimal();
?? virtual void animate();
?? virtual void draw();
?? // ...
private:
?? // data necessary for ZooAnimal's version of animate() and draw()
};
class Bear : public ZooAnimal {
public:
?? Bear();
?? void animate();
?? void draw();
?? virtual void dance();
?? // ...
private:
?? // data necessary for Bear's version of animate(), draw(), and dance()
};
The initialization of one ZooAnimal class object with another or one Bear class object with
another is straightforward and could actually be im-plemented with bitwise copy semantics (apart
from possible pointer member aliasing, which for simplicity is not considered). For example, given
Bear yogi;
Bear winnie = yogi;
yogi is initialized by the default Bear constructor. Within the constructor, yogi's vptr is
initialized to address the Bear class virtual table with code inserted by the compiler. It is
safe, therefore, to simply copy the value of yogi's vptr into winnie's. The copying of an
object's vptr value, however, ceases to be safe when an object of a base class is initialized
with an object of a class derived from it. For example, given
ZooAnimal franny = yogi;
the vptr associated with franny must not be initialized to address the Bear class virtual table
(which would be the result if the value of yogi's vptr were used in a straightforward bitwise
copy此時就不能按位拷貝). Otherwise the invocation of draw() in the following program fragment
would blow up when franny were passed to it:
??? [5]The draw() virtual function call through franny must invoke the ZooAnimal instance rather
??? than the Bear instance, even though franny is initialized with the Bear object yogi because
??? franny is a ZooAnimal object. In effect, the Bear portion of yogi is sliced off when franny
??? is initialized.
??? 虛擬語句(下面是多態的情況, 指針或引用):
??? ---------------------------------------
??? Were franny declared a reference (or were it a pointer initialized with the address of
??? yogi), then invocations of draw() through franny would invoke the Bear instance. This is
??? discussed in Section 1.3
void draw( const ZooAnimal& zoey ) { zoey.draw(); }
void foo() {
// franny's vptr must address the ZooAnimal virtual table not the Bear virtual table yogi's vptr addresses
????? ZooAnimal franny = yogi;
????? draw( yogi );?? // invoke Bear::draw()
????? draw( franny ); // invoke ZooAnimal::draw()
?? }
That is, the synthesized ZooAnimal copy constructor explicitly sets the object's vptr to the
ZooAnimal class virtual table rather than copying it from the right-hand class object.
5). Handling the Virtual Base Class Subobject:
The presence of a virtual base class also requires special handling. The initialization of one
class object with another in which there is a virtual base class subobject also invalidates
bitwise copy semantics. 又一次讓按位拷貝失效.
Each implementation's support of virtual inheritance involves the need to make each virtual base
class subobject's location within the derived class object available at runtime. Maintaining the
integrity of this location is the compiler's responsibility. Bitwise copy semantics could result
in a corruption of this location, so the compiler must intercede with its own synthesized copy
constructor. For example, in the following declaration, ZooAnimal is derived as a virtual base
class of Raccoon:
class Raccoon : public virtual ZooAnimal {
public:
?? Raccoon()????????? { /* private data initialization */ }
?? Raccoon( int val ) { /* private data initialization */ }
?? // ...
private:
?? // all necessary data
};
Compiler-generated code to invoke ZooAnimal's default constructor, initialize Raccoon's vptr,
and locate the ZooAnimal subobject within Raccoon is inserted as a prefix within the two Raccoon
constructors.
What about memberwise initialization? The presence of a virtual base class invalidates bitwise
copy semantics. (這才是Again, the problem is not when one object of a class is initialized with
a second object of the same exact class. It is when an object is initialized with an object of
one of its derived classes問題的實質). For example, consider the case in which a Raccoon object
is initialized with a RedPanda object, where RedPanda is declared as follows:
class RedPanda : public Raccoon {
public:
?? RedPanda()????????? { /* private data initialization */ }
?? RedPanda( int val ) { /* private data initialization */ }
?? // ...
private:
?? // all necessary data
};
Again, in the case of initializing one Raccoon object with another, simple bitwise copy is sufficient:
// simple bitwise copy is sufficient
Raccoon rocky;
Raccoon little_critter = rocky;
However, an attempt to initialize little_critter with a RedPanda object requires the compiler
to intercede, if subsequent programmer attempts to access its ZooAnimal subobject are to execute
properly (not an unreasonable programmer expectation!):(上一行are的主語是attempts)
// simple bitwise copy is not sufficient, compiler must explicitly initialize little_critter's
// virtual base class pointer/offset
RedPanda?? little_red;
Raccoon??? little_critter = little_red;
To summarize: We have looked at the four conditions under which bitwise copy semantics do not
hold for a class and the default copy constructor, if undeclared, is considered nontrivial
(在那四種不應進行按位拷貝的情形, 設計者如未申明則缺省的構造函數還是很有必要的). Under these
conditions, the compiler, in the absence of a declared copy constructor, must synthesize a copy
constructor in order to correctly implement the initialization of one class object with another.
In the next section, the implementation strategies for invoking the copy constructor and how
those strategies affect our programs are discussed.
posted @
2006-05-05 03:41 Jerry Cat 閱讀(1029) |
評論 (0) |
編輯 收藏
/********************************************\
|????歡迎轉載, 但請保留作者姓名和原文鏈接, 祝您進步并共勉!???? |
\********************************************/
設置條件斷點檢測內存泄露技巧一則
作者: Jerry Cat
時間: 2006/04/29
鏈接:?
http://www.shnenglu.com/jerysun0818/archive/2006/04/29/6464.html??
???? 假如你的程序有了大約212字節的內存泄露, 而你希望在內存分配時查看調用堆棧. 首先在Dbgheap.c的malloc.dbg
函數的第一行設置無條件代碼定位斷點. 然后用下面的方法將其改為條件的, 在斷點對話框里選擇Location標簽, 在
Breakpoints列表框里選擇Dbgheap.c的斷點, 單擊Condition按鈕. 在條件斷點(Breakpoint Condition)對話框的Enter
the expression to be evaluated框里輸入"nSize==212", nSize是malloc_dbg的參數, 用來確定要分配內存塊的大小.
posted @
2006-04-29 18:31 Jerry Cat 閱讀(1521) |
評論 (2) |
編輯 收藏
/********************************************\
|????歡迎轉載, 但請保留作者姓名和原文鏈接, 祝您進步并共勉!???? |
\********************************************/
Chapter 2. The Semantics of Constructors
----------------------------------------
2.1 Default Constructor Construction
作者: Jerry Cat
時間: 2006/04/27
鏈接:?http://www.shnenglu.com/jerysun0818/archive/2006/04/28/6407.html
========================================
Global objects are guaranteed to have their associated memory "zeroed out" at program start-up. Local objects allocated on the program stack and heap objects allocated on the free-store do not have their associated memory zeroed out; rather, the memory retains the arbitrary bit pattern of its previous use.
If there is no user-declared constructor for class X, a default constructor is implicitly declared…. A constructor is trivial(瑣碎, 微不足道, 啥也不干) if it is an implicitly declared default constructor….
1). Member Class Object with Default Constructor:
If a class without any constructors contains a member object of a class with a default constructor, the implicit default constructor of the class is nontrivial and the compiler needs to synthesize a default constructor for the containing class. This synthesis, however, takes place only if the constructor actually needs to be invoked.
An interesting question, then: Given the separate compilation model of C++, how does the compiler prevent synthesizing multiple default constructors, for example, one for file A.C and a second for file B.C? In practice, this is solved by having the synthesized default constructor, copy constructor, destructor, and/or assignment copy operator defined as inline. An inline function has static linkage and is therefore not visible outside the file within which it is synthesized. If the function is too complex to be inlined by the implementation, an explicit non-inline static instance is synthesized.
For example, in the following code fragment, the compiler synthesizes a default constructor for class Bar:
class Foo { public: Foo(), Foo( int ) ... };
class Bar { public: Foo foo; char *str; };
void foo_bar() {
?? Bar bar; // Bar::foo must be initialized here
?? if ( str ) { } ...
}
The synthesized default constructor contains the code necessary to invoke the class Foo default constructor on the member object Bar::foo, but it does not generate any code to initialize Bar::str. Initialization of Bar::foo is the compiler's responsibility; initialization of Bar::str is the programmer's. The synthesized default constructor might look as follows:
____To simplify our discussion, these examples ignore the insertion of the implicit this pointer.
// possible synthesis of Bar default constructor
// invoke Foo default constructor for member foo
inline Bar::Bar()
{
?? foo.Foo::Foo(); // Pseudo C++ Code
}
Again, note that the synthesized default constructor meets only the needs of the implementation, not the needs of the program.
What happens if there are multiple class member objects requiring constructor initialization? The language requires that the constructors be invoked in the order of member declaration within the class. This is accomplished by the compiler. It inserts code within each constructor, invoking the associated default constructors for each member in the order of member declaration. This code is inserted just prior to the explicitly supplied user code. For example, say we have the following three classes:
class Dopey?? { public: Dopey(); ... };
class Sneezy? { public: Sneezy( int ); Sneezy(); ... };
class Bashful { public: Bashful() ... };
and a containing class Snow_White:
class Snow_White {
public:
?? Dopey dopey;
?? Sneezy sneezy;
?? Bashful bashful;
?? // ...
private:
?? int mumble;
};
If Snow_White does not define a default constructor, a nontrivial default constructor is synthesized that invokes the three default constructors of Dopey, Sneezy, and Bashful in that order. If, on the other hand, Snow_White defines the following default constructor:
// programmer coded default constructor
Snow_White::Snow_White() : sneezy( 1024 )
{
?? mumble = 2048;
}
it is augmented as follows:
// Compiler augmented default constructor
// Pseudo C++ Code
Snow_White::Snow_White()
{
?? // insertion of member class object constructor invocations
?? dopey.Dopey::Dopey();
?? sneezy.Sneezy::Sneezy( 1024 );
?? bashful.Bashful::Bashful();
?? // explicit user code
?? mumble = 2048;
}
2). Base Class with Default Constructor:
Similarly, if a class without any constructors is derived from a base class containing a default constructor, the default constructor for the derived class is considered nontrivial and so needs to be synthesized. The synthesized default constructor of the derived class invokes the default constructor of each of its immediate base classes in the order of their declaration. To a subsequently derived class, the synthesized constructor appears no different than that of an explicitly provided default constructor.
What if the designer provides multiple constructors but no default constructor? The compiler augments each constructor with the code necessary to invoke all required default constructors. However, it does not synthesize a default constructor because of the presence of the other user-supplied constructors. If member class objects with default constructors are also present, these default constructors are also invoked梐fter the invocation of all base class constructors.
3). Class with a Virtual Function:
There are two additional cases in which a synthesized default constructor is needed:
(1). The class either declares (or inherits) a virtual function
(2). The class is derived from an inheritance chain in which one or more base classes are virtual
In both cases, in the absence of any declared constructors, implementation bookkeeping necessitates the synthesis of a default constructor. For example, given the following code fragment:
class Widget {
public:
?? virtual void flip() = 0;
?? // ...
};
void flip( const Widget& widget ) { widget.flip(); }
// presuming Bell and Whistle are derived from Widget
void foo() {
?? Bell b;? Whistle w;
?? flip( b );
?? flip( w );
}
the following two class "augmentations" occur during compilation:
(3). A virtual function table (referred to as the class vtbl in the original cfront implementation) is generated and populated with the addresses of the active virtual functions for that class.
(4). Within each class object, an additional pointer member (the vptr) is synthesized to hold the address of the associated class vtbl.
In addition, the virtual invocation of widget.flip() is rewritten to make use of widget's vptr and flip()'s entry into the associated vtbl:
?? // simplified transformation of virtual invocation:
widget.flip()
?? ( * widget.vptr[ 1 ] ) ( &widget )
where:
____1 represents flip()'s fixed index into the virtual table, and
____&widget represents the this pointer to be passed to the particular invocation of flip().
For this mechanism to work, the compiler must initialize the vptr of each Widget object (or the object of a class derived from Widget) with the address of the appropriate virtual table. For each constructor the class defines, the compiler inserts code that does just that (this is illustrated in Section 5.2). In classes that do not declare any constructors, the compiler synthesizes a default constructor in order to correctly initialize the vptr of each class object.
4). Class with a Virtual Base Class:
Virtual base class implementations vary widely across compilers. However, what is common to each implementation is the need to make the virtual base class location within each derived class object available at runtime. For example, in the following program fragment:
class X { public: int i; };
class A : public virtual X?? { public: int j; };
class B : public virtual X?? { public: double d; };
class C : public A, public B { public: int k; };
// cannot resolve location of pa->X::i at compile-time
void foo( const A* pa ) { pa->i = 1024; }
main() {
?? foo( new A );
?? foo( new C );
?? // ...
}
the compiler cannot fix the physical offset of X::i accessed through pa within foo(), since the actual type of pa can vary with each of foo()'s invocations. Rather, the compiler must transform the code doing the access so that the resolution of X::i can be delayed until runtime. In the original cfront implementation, for example, this is accomplished by inserting a pointer to each of the virtual base classes within the derived class object. All reference and pointer access of a virtual base class is achieved through the associated pointer. In our example, foo() might be rewritten as follows under this implementation strategy:
// possible compiler transformation
void foo( const A* pa ) { pa->__vbcX->i = 1024; }
where?__vbcX represents the compiler-generated pointer to the virtual base class X.
As you've no doubt guessed by now, the initialization of __vbcX (or whatever implementation mechanism is used) is accomplished during the construction of the class object. For each constructor the class defines, the compiler inserts code that permits runtime access of each virtual base class. In classes that do not declare any constructors, the compiler needs to synthesize a default constructor.
2.1 小結:
=-=-=-=-=
Programmers new to C++ often have two
common misunderstandings:
? 1. That a default constructor is synthesized for every class that does not define one
? 2. That the compiler-synthesized default constructor provides explicit default initializers for each data member declared within the class
posted @
2006-04-28 03:00 Jerry Cat 閱讀(1054) |
評論 (3) |
編輯 收藏
/********************************************\
|????歡迎轉載, 但請保留作者姓名和原文鏈接, 祝您進步并共勉!???? |
\********************************************/
比庫函數memcpy還高效的memcopy - 美妙的內嵌匯編
作者: Jerry Cat
時間: 2006/04/27
鏈接:?http://www.shnenglu.com/jerysun0818/archive/2006/04/27/6392.html
#ifdef __cplusplus
extern "C"
#endif
void *(* memcopy)( void *dest , void *src , int n );
void *memcopy_dword(void *dest, void *src, int n)
{
??? _asm {
??????? mov esi, src
??????? mov edi, dest
??????? mov ecx, n
??????? mov ebx, ecx
??????? and ecx, 3
??????? rep movsb
??????? mov ecx, ebx
??????? shr ecx, 2
??????? rep movsd
??? }
??? return dest;
}
void memcopy_init() {
? memcopy=memcopy_dword;
}
/* 數據量小但使用頻繁的memcpy之內嵌匯編內聯版 */
__inline void fbcopy( void *d, void *s, int i)
{
??? _asm {
??????? mov ecx, i
??????? mov esi, s
??????? mov edi, d
??????? rep movsb
??? }
}
posted @
2006-04-27 19:38 Jerry Cat 閱讀(5565) |
評論 (3) |
編輯 收藏
摘要: 類UNIX系統基礎:文件安全與權限
當創建一個文件的時候,系統保存了有關該文件的全部信息,包括:
"
文件的位置。
"
文件類型。
"
文件長度。
"
...
閱讀全文
posted @
2006-04-26 16:20 Jerry Cat 閱讀(1387) |
評論 (0) |
編輯 收藏