当前位置:编程学习 > wap >>

My insight C++——C++中的隐式计数

<!--[if gte mso 9]> Normal 0 7.8 pt 0 2 false false false MicrosoftInternetExplorer4 <![endif]--><!--[if gte mso 9]> <![endif]-->

C++是一种广泛使用的语言,也曾有兴趣略作研究。因为最近一段时间估计不会用它进行开发了,静下心来,谈谈我对它的理解或是发现。

 

(1) 引子

本文谈一谈C++中的隐式计数。隐式计数是一个计数器,因为他的储存空间没有显示的体现在程序代码中,故称之为“隐式”,而“计数”是说该存储空间的功能。这么一说,你首先想到的可能是C++中的new []和delete []操作符,不错,用new分配一个数组时,正是使用了“隐式计数”,才使得delete该数组指针时,能够获取到数组元素的个数,请看下面的代码,或许你并不陌生:

struct Test

{

Test() { cout << "Test()" << endl; }

~Test() { cout << "~Test()" << endl; }

};

int main()

{

Test *p = new Test[2];

*((int *)p - 1) = 1;

delete[] p;

return 0;

}

看看输出吧,构造函数被调用两次,析构函数被调用一次(在VC6.0和gcc中均是如此),毫无疑问,(int *)p - 1的位置就是一个计数器,它记录了数组数组元素的个数。


更多精彩点击 --------------------编程问答-------------------- (2) 示例1——string中的隐式计数

我们再来看看下面关于std::string的例子:

int main()

{

string s1("Hello");

string s2 = s1;

char *p = const_cast<char *>(s2.c_str());

p[0] = 'M';

cout << s1 << endl;

return 0;

}

上面的程序输出什么?是“Hello”吗?答案是不一定(我在gcc 3.4.6中是Mello)。这实际上取决于string类的实现,如果string采用了copy on write的机制,那么s1和s2实际上共享同一段内存,因此上面的代码也修改了s1的内容。当然,这都是const_cast惹的祸,常规代码对s1和s2都是能正常工作的。

上面提到了copy on write的共享机制,那么,程序又是如何决定什么时候删除该共享内存呢?答案是引用计数,如果你有兴趣,你可以查看p指针的前4个字节,发现其值为1,而再添加一个“string s3 = s1;”后,其值变为2,毫无疑问,这正是一个引用计数。

 更多精彩点击

--------------------编程问答-------------------- 3) 示例2——static中的隐式计数

再看一个关于static局部变量的例子。我们知道,如果函数中的static变量在定义时赋初值,那么只有在第一次调用该函数时,初始化才被执行,以后的调用都不再执行。那么,编译器又是怎么实现的呢?答案很简单,就是一个标志位,程序初始化时该标志位为0,函数中初始化相关的代码则演变为:检查标志位,如果是0,则对变量进行初始化,然后将标志位置1,否则跳过初始化步骤。这个标志位实际上就是一个隐式的计数器,虽然它只是一个0-1计数。

知道了编译器的这个“内幕”,你可以用下面的代码轻易的绕过初始化检查,让函数中的static变量在每次被调用时都被初始化(代码有些BT,不适者勿看)。

void Test(int initVal)

{

static int i = initVal;

cout << i << endl;

++i;

}

 

int FindAddress()

{

unsigned char *addr = (unsigned char *)&Test;

 

// There is only one instruction in Test: jmp realAddr

if (*addr == 0xe9)

{

addr = addr + *(int *)(addr + 1) + 5;

}

 

// Look forward at most 100 bytes for instruction "and eax 1"

for (int i = 0; i < 64; i++)

{

#ifdef WIN32

if (memcmp(addr + i, "\x83\xe0\x01", 3) == 0)

{

return *(int *)(addr + i - 4);

}

#else

if (addr[i+0] == 0x80 && addr[i+1] == 0x3d && addr[i+6] == 0x00)

{

return *(int *)(addr + i + 2);

}

#endif

}

 

return 0;

}

 

int main()

{

cout << "before modify: " << endl;

 

Test(0);

Test(100);

 

try

{

int flagAddress = FindAddress();

 

if (flagAddress)

{

cout << "After modify: " << endl;

*reinterpret_cast<int *>(flagAddress) = 0;

Test(1000);

}

else

{

cout << "Can not find the flag address" << endl;

}

}

catch (...)

{

cout << "There is some bug in program" << endl;

}

 

return 0;

}

代码的讲解我就不说了,注意的是FindAddress函数,其中尝试查找某种特征的指令。

--------------------编程问答-------------------- (4) 总结

上面举了几个“隐式计数”的例子,它们可能是编译器为了在程序中实现代码面上的功能,而在其中添加的额外数据结构,也可能是库源码中为你所不熟悉的数据结构(如string中的隐式计数)。了解这些深层次的实现,对查排错误或是提高效率都不无裨益。

很少写文章,写这篇文章的目的,只是希望下次你在用到C++的某个比较“怪异”的特性时,也能有自己的发现, :)。

更多精彩点击 --------------------编程问答-------------------- 看贴是学习 --------------------编程问答-------------------- 顶````````` --------------------编程问答-------------------- 呵呵,长点见识 --------------------编程问答-------------------- 一定要做个记号 --------------------编程问答-------------------- 我也不懂啊 ,就想从中能学点东西 --------------------编程问答-------------------- 很不错,值得顶!! --------------------编程问答-------------------- 不错哟,要顶啦! --------------------编程问答-------------------- 获益匪浅
--------------------编程问答-------------------- 第二个有点意思,呵呵! --------------------编程问答-------------------- 学习中 --------------------编程问答--------------------
顶!

我也顺便打个广告,本人也有支持ESRI ARCGIS的.shp文件的地图的Windows mobile 5.0/6.0 GPS手机GIS地图软件----GPS移动GIS(GPSMobileGIS),PC端的服务软件----移动GIS服务平台(GPSMobileGISServer),可成套出售,

 已经成功应用在以下系统:
1、PDA移动办公如户外,异地打卡,上班;
2、GIS林业资源监控系统;
3、GIS电力巡检系统等;
4、GIS通信资源如移动,联通,电信的管线资源巡检系统等! 

可以完成以下功能:
1,通过GPRS上网连接后台服务端程序来实时传输在户外工作采集的数据到后台数据库!

2,可以实时发回PDA的GPS信息,在后台地图上直接定位PDA用户的位置,也可以下发PDA的经纬度信息让PDA用户定位和跟踪其它PDA用户,了解自己与其它PDA的位置关系,起到定位和跟踪的作用!

3,可以发回PDA当前所在地名如在天河城附近等,实现在外面工作就知道在何时何地上班打卡的效果,同时可以在后台为相应的PDA用户设置固定时长返回一次当前位置的GPS信息确保对相应PDA用户的定位,跟踪与监控!

4,移动GIS服务平台可以对PDA用户进行登记,注销等管理,在移动GIS服务平台登记的PDA用户才可登陆此服务器,依据IMSI和IMEI号来进行登陆验证,安全可靠,

5,可以对在外面工作的PDA用户进行任务指派和任务管理如
   PDA号码:13800138000
   任务名称:测试线路
   任务说明:主要是在天河北路一带的电力设施进行检测!

6,( 此功能为信息采集的核心功能 )用户可自行设置需要采集信息的对象及其属性,指派给指定的PDA用户,如测试电路的属性模板:
    //0-编辑属性(可多个) ; 1-下拉属性(可多个) ; 2-选择属性(可多个) ; 3-大文本编辑框(可以没有此属性,但有此属性时只能有一个) ; 4-列表属性(可以没有此属性,但有此属性时只能有一个)(属性0+属性1+属性2/2+属性2%2)<=28
    name,名称,0,;beproject,所属项目,0,;type,类型,1,0:小-1:中-2:大;complete,完成,2,;remark,备注,3,;listbox,设备表,4,

7,可以实时上传文件到后台服务器,实时下载后台服务器的文件和实时更新PDA上客户端的系统!

8,可以实时采集和传输图像信息!

跟据您的需要,还可以增加其它功能!



QQ:546046182
EMail:wang921718@tom.com 


--------------------编程问答--------------------
顶!

我也顺便打个广告,本人也有支持ESRI ARCGIS的.shp文件的地图的Windows mobile 5.0/6.0 GPS手机GIS地图软件----GPS移动GIS(GPSMobileGIS),PC端的服务软件----移动GIS服务平台(GPSMobileGISServer),可成套出售,

已经成功应用在以下系统:
1、PDA移动办公如户外,异地打卡,上班;
2、GIS林业资源监控系统;
3、GIS电力巡检系统等;
4、GIS通信资源如移动,联通,电信的管线资源巡检系统等! 

可以完成以下功能:
1,通过GPRS上网连接后台服务端程序来实时传输在户外工作采集的数据到后台数据库!

2,可以实时发回PDA的GPS信息,在后台地图上直接定位PDA用户的位置,也可以下发PDA的经纬度信息让PDA用户定位和跟踪其它PDA用户,了解自己与其它PDA的位置关系,起到定位和跟踪的作用!

3,可以发回PDA当前所在地名如在天河城附近等,实现在外面工作就知道在何时何地上班打卡的效果,同时可以在后台为相应的PDA用户设置固定时长返回一次当前位置的GPS信息确保对相应PDA用户的定位,跟踪与监控!

4,移动GIS服务平台可以对PDA用户进行登记,注销等管理,在移动GIS服务平台登记的PDA用户才可登陆此服务器,依据IMSI和IMEI号来进行登陆验证,安全可靠,

5,可以对在外面工作的PDA用户进行任务指派和任务管理如
   PDA号码:13800138000
   任务名称:测试线路
   任务说明:主要是在天河北路一带的电力设施进行检测!

6,( 此功能为信息采集的核心功能 )用户可自行设置需要采集信息的对象及其属性,指派给指定的PDA用户,如测试电路的属性模板:
    //0-编辑属性(可多个) ; 1-下拉属性(可多个) ; 2-选择属性(可多个) ; 3-大文本编辑框(可以没有此属性,但有此属性时只能有一个) ; 4-列表属性(可以没有此属性,但有此属性时只能有一个)(属性0+属性1+属性2/2+属性2%2)<=28
    name,名称,0,;beproject,所属项目,0,;type,类型,1,0:小-1:中-2:大;complete,完成,2,;remark,备注,3,;listbox,设备表,4,

7,可以实时上传文件到后台服务器,实时下载后台服务器的文件和实时更新PDA上客户端的系统!

8,可以实时采集和传输图像信息!

跟据您的需要,还可以增加其它功能!



QQ:546046182
EMail:wang921718@tom.com 


--------------------编程问答-------------------- mark --------------------编程问答-------------------- 顶上 --------------------编程问答-------------------- 基本不同意LZ的看法
1,不是计数,而是内存分配时隐式赋值.
2,对于String来说是一个显式计数.
3,根本不存在那个标志位,static在全局变量初始化后被直接初始化. --------------------编程问答-------------------- 看了第一个就难得看后面的了,完全是在胡说.
麻烦你反汇编看看好不好???麻烦你不要想当然好不好??? --------------------编程问答--------------------

顶!

我也顺便打个广告,本人也有支持ESRI ARCGIS的.shp文件的地图的Windows mobile 5.0/6.0 GPS手机GIS地图软件----GPS移动GIS(GPSMobileGIS),PC端的服务软件----移动GIS服务平台(GPSMobileGISServer),可成套出售!


已经成功应用在以下系统:
1、PDA移动办公如户外,异地打卡,上班;
2、GIS林业资源监控系统;
3、GIS电力巡检系统等;
4、GIS通信资源如移动,联通,电信的管线资源巡检系统等! 



可以完成以下功能:
1,通过GPRS上网连接后台服务端程序来实时传输在户外工作采集的数据到后台数据库!

2,可以实时发回PDA的GPS信息,在后台地图上直接定位PDA用户的位置,也可以下发PDA的经纬度信息让PDA用户定位和跟踪其它PDA用户,了解自己与其它PDA的位置关系,起到定位和跟踪的作用!

3,可以发回PDA当前所在地名如在天河城附近等,实现在外面工作就知道在何时何地上班打卡的效果,同时可以在后台为相应的PDA用户设置固定时长返回一次当前位置的GPS信息确保对相应PDA用户的定位,跟踪与监控!

4,移动GIS服务平台可以对PDA用户进行登记,注销等管理,在移动GIS服务平台登记的PDA用户才可登陆此服务器,依据IMSI和IMEI号来进行登陆验证,安全可靠,

5,可以对在外面工作的PDA用户进行任务指派和任务管理如
   PDA号码:13800138000
   任务名称:测试线路
   任务说明:主要是在天河北路一带的电力设施进行检测!

6,( 此功能为信息采集的核心功能 )用户可自行设置需要采集信息的对象及其属性,指派给指定的PDA用户,如测试电路的属性模板:
    //0-编辑属性(可多个) ; 1-下拉属性(可多个) ; 2-选择属性(可多个) ; 3-大文本编辑框(可以没有此属性,但有此属性时只能有一个) ; 4-列表属性(可以没有此属性,但有此属性时只能有一个)(属性0+属性1+属性2/2+属性2%2)<=28
    name,名称,0,;beproject,所属项目,0,;type,类型,1,0:小-1:中-2:大;complete,完成,2,;remark,备注,3,;listbox,设备表,4,

7,可以实时上传文件到后台服务器,实时下载后台服务器的文件和实时更新PDA上客户端的系统!

8,可以实时采集和传输图像信息!

跟据您的需要,还可以增加其它功能!

同时出售ICAD源码2000版,保证能在VC6.0下编译通过!

QQ:546046182
EMail:wang921718@tom.com 


--------------------编程问答-------------------- mark --------------------编程问答-------------------- 不懂LZ想实现什么,本来人家想向用户隐藏的东西,却被LZ易做图地挖出来了。。就像我写一个类,里面有个私有成员,LZ偏要把这个私有成员挖出来。。破坏了语言自身的规则。。

要了解这些工作原理看代码不就行了嘛。。何必去猜测,CRT和STRING都有代码,说不定被你这样一写,程序就Crash了。

1:内存管理器自身要记住分配内存快的大小,不管是c++的new/delete还是c的malloc和/free,这个是语言自身的一个实现,而不是C++中的什么隐式计数,况且delete是C++的一个操作符!

2和3.。。没兴趣再回答。。 --------------------编程问答-------------------- mark --------------------编程问答-------------------- mark --------------------编程问答-------------------- Mark --------------------编程问答-------------------- copy on write?现在还有使用这个实现的字符串? --------------------编程问答-------------------- 看过一个垃圾回收器,跟LZ说的有点类似,不过计数器是自己设计,只是让他更加智能,不知道原来的是不是如此 --------------------编程问答-------------------- 我也觉得这样不好。应该是抽象出来的。学习下吧 --------------------编程问答-------------------- mark --------------------编程问答-------------------- 获益匪浅  --------------------编程问答-------------------- MARK --------------------编程问答-------------------- 学习 --------------------编程问答-------------------- 学习 MARK
--------------------编程问答-------------------- 好贴留名 --------------------编程问答-------------------- 但是不应该写出依赖这些实现的代码,那简直就是灾难!!! --------------------编程问答-------------------- mark --------------------编程问答-------------------- mark --------------------编程问答-------------------- 学习了。 --------------------编程问答-------------------- 都有些不对

那些计数是实现着的做法,标准没有规定了用那种方法的实现.
只能说某些实现的隐士计数,而不能说是C++语言规定的隐式计数 --------------------编程问答-------------------- 看不太明白 --------------------编程问答-------------------- 对楼主钻研的精神赞扬! --------------------编程问答-------------------- I always think they are bugs. --------------------编程问答-------------------- 这个和编译器的实现有关,所有和C++语言本身其实毫无关系……(第二条的话不算是C++语言本身的问题吧,只是实际类的问题) --------------------编程问答-------------------- 为什么 第一个代码 里面, 如果 类 不写 析构函数, *((int *)p - 1) 就 不对了 , 
 
求解!!! --------------------编程问答-------------------- mark --------------------编程问答-------------------- 谢谢 --------------------编程问答-------------------- 顶 --------------------编程问答-------------------- 了解了 --------------------编程问答-------------------- 顶一下,很好 --------------------编程问答-------------------- 有争论的帖子,不看。 --------------------编程问答-------------------- 怎么看引用次数?我加了句cout<<*((int*)p-1);但是结果不对哦,求教
引用 1 楼 tomato_potato 的回复:
(2) 示例1——string中的隐式计数 

我们再来看看下面关于std::string的例子: 

int main() 



string s1("Hello"); 

string s2 = s1; 

char *p = const_cast <char *>(s2.c_str()); 

p[0] = 'M'; 

cout < < s1 < < endl; 

return 0; 



上面的程序输出什么?是“Hello”吗?答案是不一定(我在gcc 3.4.6中是Mello)。这实际上取决于string类的实现,如果string采用了copy on write的机制,那么s1和s2实际上共享同一段…
--------------------编程问答-------------------- 要是有一个类似sizeof的关键字可以返回new分配的内存大小就好了.
实际上没有,说明new[]方式分配的内存其"隐式计数"的位置和存在方式是不确定的. --------------------编程问答--------------------
引用 51 楼 xinustc 的回复:
怎么看引用次数?我加了句cout < <*((int*)p-1);但是结果不对哦,求教 
引用 1 楼 tomato_potato 的回复:
(2) 示例1——string中的隐式计数 

我们再来看看下面关于std::string的例子: 

int main() 



string s1("Hello"); 

string s2 = s1; 

char *p = const_cast <char *>(s2.c_str()); 

p[0] = 'M'; 

cout < < s1 < < endl; 

return 0; 



上面的程序输出什么?是“Hello”吗?答案是不…


这个东西和编绎器相关的,不同的编绎器有不同的实现,我的 vs2005也不行 --------------------编程问答-------------------- mark --------------------编程问答-------------------- 顶  学习一下 --------------------编程问答-------------------- 学习一下 --------------------编程问答-------------------- 先顶再看!! --------------------编程问答-------------------- compiler dependents --------------------编程问答-------------------- 麻仁棵  --------------------编程问答-------------------- --------------------编程问答-------------------- 楼主好人啊 感动ing --------------------编程问答-------------------- 不错 仔细思考 --------------------编程问答-------------------- --------------------编程问答-------------------- 感谢楼主分享经验 --------------------编程问答-------------------- 受教了! --------------------编程问答--------------------
引用 190 楼 MSTOP 的回复:
引用 189 楼 test_000_012 的回复:
引用 184 楼 kkkgho 的回复:
版主也是人,他们没拿工资,为什么要为你服务?

他们是为CSDN服务的

各位版主的奴才意识相当到位...............

这鸟人真是已易做图到了无可复加....
看来我不易做图妈你都不知道谁是你爹了.


看看此版主的此等留言.............

更多版主的更多精彩留言就在下面链接:

http://topic.csdn.net/u/20081119/11/bda8bc5d-98d0-45ee-a1c1-86209d7f121d.html?seed=1991168656#replyachor

--------------------编程问答-------------------- MARK 学习一下 --------------------编程问答-------------------- 领教了,看来自己不是一般的无知啊。。。。 --------------------编程问答-------------------- 学习 --------------------编程问答-------------------- 长见识 --------------------编程问答-------------------- 长点见识 --------------------编程问答-------------------- 搂主最后那个程序实例有没有运行成功呢?是针对某个编译器起作用吧? --------------------编程问答-------------------- 很不错,值得顶!! --------------------编程问答-------------------- 等有时间,看看,先MRAR一下,看看c++隐式计数到底是怎么一回事。
补充:移动开发 ,  超极本开发
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,