LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 871|回复: 3

构造函数中抛出异常造成静态成员重新初始化的问题

[复制链接]
发表于 2006-10-1 20:09:29 | 显示全部楼层 |阅读模式
写了一个支持对象计数的类,代码如下:

  1. /**
  2. * @file Counted.h
  3. * This is the header of class Counted.
  4. */

  5. #ifndef COUNTED_H_
  6. #define COUNTED_H_

  7. #include <iostream>

  8. namespace myclass
  9. {
  10.         /**
  11.          * @class Counted
  12.          * @brief The base class used to count objects.
  13.          *
  14.          * This class is used to confine the number of objects.
  15.          * If the number exceeds the max number, then a exception
  16.          * called TooManyObjects will be throwed out.
  17.          */
  18.         template <class BeingCounted>
  19.         class Counted
  20.         {
  21.         public:
  22.                 /**
  23.                  * @class TooManyObjects
  24.                  * @brief The class of exception which will be throwed
  25.                  * while there are too many objects.
  26.                  *
  27.                  * This class is a member class of Counted, and will be
  28.                  * throwed only by the class Counted. In the derived class
  29.                  * of Counted, the class should be declared as public, so
  30.                  * that the exception can be captured.
  31.                  */
  32.                 class TooManyObjects
  33.                 {
  34.                         public:
  35.                                 TooManyObjects(){};
  36.                                 virtual ~TooManyObjects(){};
  37.                 };
  38.                
  39.                 /**
  40.                  * @fun        objectCount
  41.                  * @brief Provider the number of objects of the object.
  42.                  * @return The number of objects.
  43.                  *
  44.                  * Get the number of objects for the derived class.
  45.                  */
  46.                 static int objectCount();
  47.                        
  48.         public:
  49.                 Counted();
  50.                 Counted(const Counted& rhs);
  51.                 virtual ~Counted();
  52.                        
  53.         private:
  54.                 static size_t numObjects;        ///< The number of objects.
  55.                 static const size_t maxObjects;        ///< The max number of objects.
  56.                        
  57.                 /**
  58.                  * @fun init
  59.                  * @brief Intialize the object.
  60.                  *
  61.                  * Because the constructor and the copy constructor have
  62.                  * the operations, so a function is needed here to avoid
  63.                  * the repeat code.
  64.                  */
  65.                 void init();
  66.         };
  67.        
  68.         template<class BeingCounted>
  69.         size_t Counted<BeingCounted>::numObjects = 0;        // Note here the value of numObjects is 0.

  70. //        template<class BeingCounted>
  71. //        const size_t Counted<BeingCounted>::maxObjects = 1;
  72.        
  73.         template<class BeingCounted>
  74.         int Counted<BeingCounted>::objectCount()
  75.         {
  76.                 return numObjects;
  77.         }

  78.         template<class BeingCounted>
  79.         Counted<BeingCounted>::Counted()
  80.         {
  81.                 init();
  82.         }

  83.         template<class BeingCounted>
  84.         Counted<BeingCounted>::Counted(const Counted <BeingCounted>&)
  85.         {
  86.                 init();
  87.         }

  88.         template<class BeingCounted>
  89.         Counted<BeingCounted>::~Counted()
  90.         {
  91.                 -- numObjects;
  92.         }

  93.         template<class BeingCounted>
  94.         void Counted<BeingCounted>::init()
  95.         {
  96.                 if(numObjects >= maxObjects)
  97.                 {
  98.                         throw TooManyObjects();
  99.                 }
  100.                 ++ numObjects;
  101.         }
  102. }

  103. #endif /*COUNTED_H_*/
复制代码


  1. // file TestCounted.h
  2. #ifndef TESTCOUNTED_H_
  3. #define TESTCOUNTED_H_

  4. #include "Counted.h"

  5. namespace myclass
  6. {
  7.         class TestCounted: Counted<TestCounted>
  8.         {
  9.         public:
  10.                 TestCounted();
  11.                 virtual ~TestCounted();
  12.                 using Counted<TestCounted>::objectCount;
  13.                 using Counted<TestCounted>::TooManyObjects;
  14.         };
  15. }

  16. #endif /*TESTCOUNTED_H_*/
复制代码


  1. // file TestCounted.cpp
  2. #include "TestCounted.h"

  3.         namespace myclass
  4.         {
  5.         template<typename TestCounted> const size_t Counted<TestCounted>::maxObjects = 2;
  6.        
  7.         TestCounted::TestCounted()
  8.         {
  9.         }
  10.        
  11.         TestCounted::~TestCounted()
  12.         {
  13.         }
  14. }

复制代码


  1. // file main.cpp
  2. #include <iostream>
  3. #include "TestCounted.h"
  4. #include "Counted.h"

  5. using namespace std;
  6. using namespace myclass;

  7. int main()
  8. {
  9.         try
  10.         {
  11.                 TestCounted t1;
  12.                 TestCounted t2;
  13.                 TestCounted t3;       
  14.         }
  15.         catch(TestCounted::TooManyObjects& e)
  16.         {
  17.                 cout << "The number of objects is " << TestCounted::objectCount() << "!\n";
  18.                 //throw;
  19.         }
  20.         return (0);
  21. }
复制代码


其中Counted是支持对象计数的基类,当对象个数超出设定的最大数值时,有一个异常将被抛出。设定的对象最大个数是2.TestCounted私有继承了Counted,因此具有了对象计数能力。

在main函数中,创建3个TestCounted对象,这将导致异常被抛出,通过try-catch块捕捉,然后输出此时的对象个数,却惊奇地发现输出的对象个数为0!也就是说,类的静态成员numObjects又被重新初始化了。编译环境是Gcc4.0.3。

请问这是什么原因造成的?是否属于C++的异常机制?谢谢!
发表于 2006-10-2 02:11:23 | 显示全部楼层
类的构造函数不应该设计为有可能抛异常,构造函数应该设计为异常安全的
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-10-2 09:37:38 | 显示全部楼层
Post by svenwang
类的构造函数不应该设计为有可能抛异常,构造函数应该设计为异常安全的


嗯,受教了。可是如果需要检测对象构造失败的情况,就必须在构造函数中使用异常。异常抛出时,C++标准规定对象里已经构造好的字对象将被逆序地析构。怪就怪在还会将静态成员重新初始化。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-10-2 10:53:05 | 显示全部楼层
解决了,设计上的问题。t1和t2在catch块中时已经被析构了,因此计数为0.
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表