CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
可用分押宝游戏火热进行中... 专题改版:Java Web 专题
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  C/C++ >  工具平台和程序库

一个关于ctor和dtor的问题:

楼主chenlee()2003-09-01 21:30:17 在 C/C++ / 工具平台和程序库 提问

有如下一段程序,测试环境:VC.net   2003,关闭所有优化  
   
  struct   A  
  {  
          ~A()   {   printf("~A   ");   }  
  };  
   
  struct   B   :   public   A  
  {  
          ~B()   {   printf("~B   ");   }  
  };  
   
  void   main()  
  {  
          {  
                  const   A   &   a   =   B();  
          }  
  }  
   
  我认为这段程序应当只产生一个B的实例,  
   
  而程序的输出却是:~B   ~A   ~B   ~A  
   
  也就是说A和B的析构函数各被调用了两次,猜想是由于临时变量引起的。  
   
  但当我给A或者B增加一个缺省构造函数,比如:A()   {}   或者   B(){}后,  
   
  输出结果就变成了:~B   ~A  
   
  请问各位C++牛人,能否解释这个现象?是VC的bug还是C++语言本身所致?  
  问题点数:100、回复次数:19Top

1 楼sevecol(sevecol.blogone.net)回复于 2003-09-01 22:02:03 得分 40

关注,他的编译器的行为呢?  
  Top

2 楼oopig(面向对象的猪)回复于 2003-09-01 22:05:01 得分 40

vc6.0和vc7有这个现象,dev-c++4.9.8.0和g++3.2没有这个现象。和继承也没有关系。  
  而且如果在vc中把语句外面的那一对花括号去掉,则只创建一个临时对象,否则创建两个临时对象。  
  我倾向于认为这是vc的一个“特性”。还是要翻翻《c++程序语言设计》或者c++标准才能下结论。  
  Top

3 楼oopig(面向对象的猪)回复于 2003-09-01 22:15:37 得分 0

不好意思,搞错了。  
  不论是否去掉多出来的那对花括号,vc都是创建两个对象。bcb5.0的行为和vc一致。  
  Top

4 楼oopig(面向对象的猪)回复于 2003-09-01 23:10:35 得分 0

变形代码:  
  {  
          B   a;  
          const   B   &b   =   &a;  
  }  
  以上代码的输出为:~B。  
   
  const   A   &   a   =   B();这行代码大概可以这么理解:  
  1。B()这个临时对象的生命期只存在于这个表达式  
  2。常量引用b的生命期则存在于两个花括号之间  
  3。为了解决1和2的矛盾,有两种解决办法:创建两个变量或者实际上延长B()临时变量的生命周期。看来vc和bcb选择了前者而g++选择了后者。至于那种方法符合c++标准,又或者c++标准对此没有规定,需要继续考证。Top

5 楼svenwang(svenwang)回复于 2003-09-01 23:34:55 得分 0

upTop

6 楼oopig(面向对象的猪)回复于 2003-09-01 23:38:18 得分 0

《c++程序设计语言》p227有句话:  
  除非一个临时对象被约束到某个引用,或者被用于做命名对象的初始化,否则它将总在建立它的那个完整表达式结束时销毁。所谓完整表达式就是那种不是其他表达式的子表达式的表达式。  
  按照我对这句话的理解,vc和bcb的做法不符合c++标准。  
  Top

7 楼chenlee()回复于 2003-09-02 10:52:27 得分 0

我当初用内层的花括号只是为了限定a的生存期,方便调试。  
  不管一对还是两对,程序的结果都一样。  
  Top

8 楼sevecol(sevecol.blogone.net)回复于 2003-09-02 16:33:28 得分 0

我认为这个符合C++标准的。  
   
  首先这些临时对象都是按照C++标准所规定生存周期存活的。在离开了{},那个邦定到引用的临时对象析构。  
   
  第二,在C++标准中没有提到临时对象产生索要必须遵循规则(我没找到),我觉得这是编译器优化的选择。Top

9 楼oopig(面向对象的猪)回复于 2003-09-02 16:57:54 得分 0

sevecol(看什么看...):那你对这句话怎么理解?  
  除非一个临时对象被约束到某个引用,或者被用于做命名对象的初始化,否则它将总在建立它的那个完整表达式结束时销毁。所谓完整表达式就是那种不是其他表达式的子表达式的表达式。  
  Top

10 楼sevecol(sevecol.blogone.net)回复于 2003-09-02 17:27:22 得分 0

const   A   &   a   =   B();  
  这个就是临时对象绑定到引用上,这个临时对象只有到了被初始化的引用的生命周期结束时被销毁,也就是{}的最后被销毁。  
  这个临时对象不管是在你有没有构造函数的时候都被正确的处理。  
   
  关键是VC创建的另一个临时对象,这个临时对象,在这个全的表达式后销毁。而C++标准对于编译器如何产生临时对象好像没有具体的规定,只是规定了临时对象的生命周期和语义的表达一致。  
   
  我认为对于没有构造函数的情况下,VC产生两个临时变量也是符合C++标准的。  
  同样的有构造函数情况下(可能会引发某种优化),产生一个临时对象也是符合C++标准的。  
   
  当然上面成立的前提是所产生的临时对象满足C++标准对于临时对象生存周期的约束。Top

11 楼plainsong(短歌)()回复于 2003-09-02 18:36:25 得分 10

BCB6中:  
      输出为~A   ~B   ~A,大概是A和B各有一个对象,发生了切片。  
  而VC6中:  
      ~B   ~A   ~B   ~A,大概是有两个B对象产生。  
  当把A的析构改为virtual时,全都正常(输出为~B~A)。  
   
  问题是在基类析构非多态时子类的向上映射真的有意义吗?Top

12 楼oopig(面向对象的猪)回复于 2003-09-02 18:48:23 得分 0

>>而C++标准对于编译器如何产生临时对象好像没有具体的规定,只是规定了临时对象的生命周期和语义的表达一致。  
  所谓临时变量我认为就是在完整表达式中建立的匿名对象,如果不是这样那就成了局部变量了。结合《c++程序设计语言》上的描述,我认为vc的这种行为是不符合c++标准的。Top

13 楼oopig(面向对象的猪)回复于 2003-09-02 18:50:11 得分 0

plainsong(短歌):  
  我试了VC下const   B   &b   =   B();这个语句还是创建了两个对象,所以和基类析构非多态时子类的向上映射没有什么关系。  
   
  Top

14 楼sevecol(sevecol.blogone.net)回复于 2003-09-02 18:58:11 得分 0

to   oopig(面向对象的猪):  
   
            C++标准中好象没有规定产生多少个临时对象吧?只要产生的临时对象满足临时对象的生命周期的约束,我认为就没有不符和C++的标准.  
  Top

15 楼oopig(面向对象的猪)回复于 2003-09-02 19:07:39 得分 0

sevecol(如果问题解决,就请结贴):  
  那么B();这个语句产生两个或者三个或者n个对象都不算是不符合c++标准了?Top

16 楼sevecol(sevecol.blogone.net)回复于 2003-09-02 19:14:48 得分 0

我记得在Inside   The   C++   Object   Model中文版里面的关于临时对象有说  
  C++   Standard允许编译器对于临时对象的产生有完全的自由度Top

17 楼chenlee()回复于 2003-09-02 20:09:38 得分 0

在C++   Standard   8.5.3一节中找到了关于引用时临时变量的详细说明:  
   
  =============================================================================  
   
  If   the   initializer   expression   is   an   rvalue,   with   T2   a   class   type,  
  and   “cv1   T1”   is   referencecompatible   with   “cv2   T2,”   the   reference  
  is   bound   in   one   of   the   following   ways   (the   choice   is   implementationdefined)   :  
   
      -   The   reference   is   bound   to   the   object   represented   by   the   rvalue  
              (see   3.10)   or   to   a   subobject   within   that   object.  
   
      -   A   temporary   of   type   “cv1   T2”   [sic]   is   created,   and   a   constructor   is  
          called   to   copy   the   entire   rvalue   object   into   the   temporary.   The   reference  
          is   bound   to   the   temporary   or   to   a   subobject   within   the   temporary.  
   
  The   constructor   that   would   be   used   to   make   the   copy   shall   be   callable   whether  
  or   not   the   copy   is   actually   done.  
   
  [Example:  
      struct   A   {   };  
      struct   B   :   public   A   {   }   b;  
      extern   B   f();  
      const   A&   rca   =   f();   //   Either   bound   to   the   A   subobject   of   the   B   rvalue,  
                                              //   or   the   entire   B   object   is   copied   and   the   reference  
                                              //   is   bound   to   the   A   subobject   of   the   copy  
  —end   example]  
   
  =============================================================================  
   
  由上可知,const   A   &   a   =   B();  
   
  如果采用第一种方法,则只有一个临时变量;  
  而采用第二种方法,则有两个临时变量。  
   
  由此可见VC并没有违反C++的规定。  
   
  各位看我的理解是否正确?  
   
  Top

18 楼xueweizhong(薛卫忠)回复于 2003-09-04 10:38:41 得分 10

to   plainsong(短歌):  
  >BCB6中:  
  >     输出为~A   ~B   ~A,大概是A和B各有一个对象,发生了切片  
   
  1)我特意仔细核对了一下,CBUILDER在  
        当且仅当   类A或类B拥有trivial-ctor时   出现你说的这种情况。  
   
  2)其他情况下表现为和g++,CC同样的情况。  
   
  3)很明显,  
        在A或B拥有trivial-ctor时的BORLAND的行为不符合C++98标准,  
        应该算是一个BORLAND   COMPILER的一个BUG。  
  Top

19 楼chenlee()回复于 2003-09-05 09:47:59 得分 0

看来就是这样了。  
   
  结贴!!Top

相关问题

  • private copy ctor??
  • c++中ctor是什么意思?
  • member function definition looks like a ctor, but name does not match enclosing class
  • 请问ctor是什么东东,看不懂这条注释
  • 这是什么意思啊?error LNK2020: 无法解析的标记(0A00007A) pnl.CContextSaveXML.__dtor
  • mysql和#和ISA???????
  • "=" 和 "like"
  • 和平
  • 求和
  • datagrid和ado.net和odbc

关键词

  • c++
  • c++程序设计
  • 函数
  • 编译器
  • 括号
  • vc
  • bcb
  • 语句
  • 代码
  • 临时对象

得分解答快速导航

  • 帖主:chenlee
  • sevecol
  • oopig
  • plainsong
  • xueweizhong

相关链接

  • C/C++ Blog
  • C/C++类图书
  • C/C++类源码下载

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
世纪乐知(北京)网络技术有限公司 版权所有, 京 ICP 证 020026 号
北京创新乐知广告有限公司 提供技术支持
Copyright © 2000-2007, CSDN.NET, All Rights Reserved
GongshangLogo