asm, c, c++ are my all
-- Core In Computer
posts - 139,  comments - 123,  trackbacks - 0

/********************************************\
|    欢迎转载, 但请保留作者姓名和原文链接, 祝您进步并共勉!     |
\********************************************/


C++对象模型(6) -  Program Transformation Semantics

作者: Jerry Cat
时间: 2006/05/11
链接: 
http://www.cppblog.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 阅读(511) | 评论 (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 阅读(1355) | 评论 (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 阅读(424) | 评论 (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 阅读(347) | 评论 (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 阅读(210) | 评论 (0)编辑 收藏

/********************************************\
|    欢迎转载, 但请保留作者姓名和原文链接, 祝您进步并共勉!     |
\********************************************/


C++对象模型(5) -  Copy Constructor Construction

作者: Jerry Cat
时间: 2006/05/05
链接: http://www.cppblog.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 阅读(960) | 评论 (0)编辑 收藏
/********************************************\
|    欢迎转载, 但请保留作者姓名和原文链接, 祝您进步并共勉!     |
\********************************************/


设置条件断点检测内存泄露技巧一则

作者: Jerry Cat
时间: 2006/04/29
链接: 
http://www.cppblog.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 阅读(1383) | 评论 (2)编辑 收藏

/********************************************\
|    欢迎转载, 但请保留作者姓名和原文链接, 祝您进步并共勉!     |
\********************************************/


Chapter 2. The Semantics of Constructors
----------------------------------------
2.1 Default Constructor Construction

作者: Jerry Cat
时间: 2006/04/27
链接: http://www.cppblog.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 阅读(1029) | 评论 (3)编辑 收藏

/********************************************\
|    欢迎转载, 但请保留作者姓名和原文链接, 祝您进步并共勉!     |
\********************************************/


比库函数memcpy还高效的memcopy - 美妙的内嵌汇编

作者: Jerry Cat
时间: 2006/04/27
链接: http://www.cppblog.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 阅读(5015) | 评论 (3)编辑 收藏
     摘要: 类UNIX系统基础:文件安全与权限 当创建一个文件的时候,系统保存了有关该文件的全部信息,包括: " 文件的位置。 " 文件类型。 " 文件长度。 " ...  阅读全文
posted @ 2006-04-26 16:20 Jerry Cat 阅读(1364) | 评论 (0)编辑 收藏
仅列出标题
共14页: First 6 7 8 9 10 11 12 13 14 

<2006年6月>
28293031123
45678910
11121314151617
18192021222324
2526272829301
2345678

常用链接

留言簿(7)

随笔档案

最新随笔

搜索

  •  

最新评论

阅读排行榜

评论排行榜