某日,武大郎卖完炊饼回屋,见潘金莲和西门庆在床上巫山云雨,大怒。
武大郎说:西门小儿,潘金莲是我老婆,你上她干甚?
西门庆回应:她是你老婆,这是宪法规定的。我只是替你保护和使用而已。
武大郎抄起擀面棍。
西门庆抽出杀猪刀。
僵持…
武大郎心想:西门庆可是这片土地的老大。手下有一大队人马,我奈他何!
西门庆说:我又不要你老婆的所有权。她永远是你老婆嘛。
武大郎说:只要你不剥夺我对她的“所有权”
西门庆说:我只要“管理权”,“使用权”。
武大郎长时间见不到潘金莲。很想和她亲热一番。去找西门庆。
西门庆说:可以啊。我出让她给你一段时间,以70分钟为限,70分钟之后重新计时。每70分钟收费300块。
武大郎愕然。
西门庆说:对我,这叫“美女出让金”;对你,这叫“美女使用金”。
武大郎心想:既然我仅仅拥有法律下的所有权,而西门庆对潘金莲才拥有真正的“管理权”,我要使用她,也应该缴纳“使用金”,这似乎天经地义啊。
武大郎给西门庆300块,云雨去了。边云雨边嘲笑其他付不起300块的穷男人。
在windows平台下debug模式有效
#ifdef WIN32
typedef struct tagTHREADNAME_INFO
{
DWORD dwType; // must be 0x1000
LPCSTR szName; // pointer to name (in user addr space)
DWORD dwThreadID; // thread ID (-1=caller thread)
DWORD dwFlags; // reserved for future use, must be zero
} THREADNAME_INFO;
#endif
void SetThreadName(const char* format, ...)
{
// This isn't supported on *nix
va_list ap;
va_start(ap, format);
#ifdef WIN32
char thread_name[200];
vsnprintf(thread_name, 200, format, ap);
THREADNAME_INFO info;
info.dwType = 0×1000;
info.dwThreadID = GetCurrentThreadId();
info.dwFlags = 0;
info.szName = thread_name;
__try
{
#ifdef _WIN64
RaiseException(0×406D1388, 0, sizeof(info)/sizeof(DWORD), (ULONG_PTR*)&info);
#else
RaiseException(0×406D1388, 0, sizeof(info)/sizeof(DWORD), (DWORD*)&info);
#endif
}
__except(EXCEPTION_CONTINUE_EXECUTION)
{
}
#endif
va_end(ap);
}
断断续续读完这本书,花了接近两年时间,做游戏之前开始读,公司的项目做的差不多了,才读完第一遍。刚进去的时候是新人,转眼成了老鸟。
初读这本书的缘由,只是逆向的时候职业习惯对于C系语言地址+偏移的敏感,不解类的构造和传统的struct在内存布局上的区别和暗中手脚。读完之后,ADT,布局,虚函数表,临时对象,模板绑定,运行期识别等实现方式了然于胸。
书的上半部分已经解了我的惑,阐述的内容集中于C++之于C的内存布局和编译器在强类型语法上的支持及实现手法,表现于vptr,virtual public之实现,重在编译和链接期。
下半部分对new/placement new,全局对象预分配,临时对象的生成时机,EH, RTTI, type_info,type_id,以及dynamic_cast之于引用和指针都做了独到的讲解,重在运行期的数据结构组织查询方式。
全书每一个测试都贯穿了执行效率和代码复杂度上代价互换的思考,到后期的一条测试主线甚至加进了各家编译器之于不同应用平台的特化性/效率取舍,受益匪浅。
以下是感悟了:
C++之尤雅 在于有效解决了函数名重用的问题 vtable的实际作用一方面在于解决了无数的if elseif,另一方面避免了系列函数名之累赘。
然而局限也在源于此,无论vtable也好,EH也好,RTTI也好,都是在编译期硬编码了某些地址或者执行期依赖的结构信息,在视野扩展到操作系统的跨进程环境下,不同进程内虚拟地址就无法共享了。
回过头来看 ,C++编译器上的很多东西,MFC也有一些蹩脚实现。书的最后几句话讲了COM相关的东西,如COM当初开发组的leader所言,微软之所以要做COM,初衷只是解决进程间通信的问题。
最后抄一段代码来结束这半年的开发和学习生活。
#include "stdafx.h"
#include <iostream>
#include <typeinfo>
using namespace std;
class B
{
};
class D :public B
{
};
int _tmain(int argc, _TCHAR* argv[])
{
B *pb = new B;
D *pd = new D;
cout <<”pb’s type name = ” << typeid(pb).name() << endl;
cout <<”pd’s type name = ” << typeid(pd).name() << endl;
cout <<”pb’s type rawname = ” << typeid(pb).raw_name() << endl;
cout <<”pd’s type rawname = ” << typeid(pd).raw_name() << endl;
system(”pause”);
return 0;
}
这本书忙中偷闲读了半年有余才看完4章 每次总是看过几页又得往回翻 年底重拾此书 写下一些代码调试了书中知识点
发现毕业几年来第一次碰到一本书写得如此有味道
前几章的内容不外乎讲各厂家编译器里对象初始化、内存布局、内存管理、虚表的实现细节
细读来 以前理解不是很深刻的多重继承下指针转化的偏移开销 初始化表和继承member的执行顺序 派生类和基类的布局方式 虚函数表的生成和调用等问题都收益颇多
太久没有更新过这个地方了 花了点时间写的测试代码贴上来献献丑
#include "stdafx.h"
#include <windows.h>
class Point2d
{
public:
Point2d()
{
x= 0.1;
y=0.2;
}
~Point2d()
{
}
public:
virtual DWORD getPos(){return pos;};
public:
float x;
float y;
static DWORD pos;
};
DWORD Point2d::pos = 3;
int _tmain(int argc, _TCHAR* argv[])
{
Point2d point2d;
//取类基址 地址应该在栈上
void* p = (void*)&point2d;
//取vptr地址 ms的编译器把vptr放在类开头
unsigned int pVptr = (unsigned int)*(unsigned int*)p;
//取vtable地址
unsigned int* p2 = (unsigned int*)pVptr;
//vtable里第一个DWORD就是getPos的指针
unsigned int addr = *p2;
//调用虚函数getPos
DWORD ret = 0;
__asm
{
push eax;
mov eax,addr;
call eax;
mov ret,eax;
pop eax;
}
printf(”getPos= %u\n”,ret);
printf(”&point2d.x = %p\n”,&point2d.x);
printf(”&point2d.y = %p\n”,&point2d.y);
printf(”&Point2d::x = %p\n”,&Point2d::x);
printf(”&Point2d::y = %p\n”,&Point2d::y);
printf(”&point2d.pos = %p\n”,&point2d.pos);
printf(”&Point2d::pos = %p\n”,&Point2d::pos);
return 0;
}
一个vc6的项目放到vc8下重新编译 这里死活过不去 查了些资料无果 后来翻到一句老外的回答
If AfxGetMainWnd is called from the application’s primary thread, it returns the application’s main window according to the above rules. If the function is called from a secondary thread in the application, the function returns the main window associated with the thread that made the call.
大概意思就是说在子线程里面调用AfxGetMainWnd()返回的是和当前线程相关联的窗体句柄而不是当前程序的主窗体句柄。不知道这是不是vc8的一个改变,也没时间去细查。
解决方法1:
CWnd* m_pCWnd = NULL;
在OnInitDialog里 m_pCWnd = AfxGetMainWnd();
解决方法2:
调用AfxGetMainWnd()的地方替换成AfxGetApp()->m_pMainWnd
编译后运行问题解决


分享到做啥
分享到收客
