模板成员函数,静态局部变量和销毁顺序

时间:2013-08-23 23:49:22

标签: c++ templates memory-management c++11 static

首先,抱歉我的英文:

我设计了一个小库来管理我的程序使用的内存。主要是它实现了一种具有内存管理目的的共享对象。我有以下类(我省略了其他成员和函数,我不需要在这里解释我的问题):

  • 名为packet的参数化结构,包含T类型的子对象和计数器:
template<class T>
struct packet
{
   T t;
   unsigned counter;
};
  • 一个名为ptrstack的参数类:一个带有析构函数的stack,当调用析构函数时,它会为堆栈包含的每个指针调用delete
template<typename T>
struct ptrstack : public std::stack<T*>
{
  ~ptrstack()
  {
      while(!this->empty()) {
        delete this->top();
        this->pop();
      }
  }
};
  • 一个名为pool的类,带有静态参数函数(当然还有其他代码),返回对ptrstack的引用:
class pool
{
   template<class T>
   using stack_tp = ptrstack<packet<T> >;

public:
   template<class T>
   static stack_tp<T>& get()
   {
     static stack_tp<T> pool;

     return pool;
   }
};
  • 最后,参数类shared_obj
template<typename T>
class shared_obj
{ /* Members (see below) */ };
  • 用户类继承shared_obj
struct internals_t; // definition in a .cpp source code (pImpl idiom).

// `shared_obj` uses only pointer to its type parameter.
class user_t : public shared_obj<internals_t>
{
  // member functions accessing its internal pointer. 
  // `user_t` is very light. It only mantains a pointer, but it could be used as
  // a common object.
  // moreover, I can work with dynamic objects without using new and delete
  // since the memory is managed by shared_obj
};

构造,分配/复制和销毁从根本上执行以下操作:

  • 每次想要创建新的shared_obj<T>时,都会在堆中创建packet<T>*
  • 每次复制shared_obj<T>时,其关联数据包的计数器都会递增。
  • 每次调用shared_obj<T>的析构函数时,其关联数据包的计数器都会递减。
  • 如果其关联数据包的计数器达到0,则其关联指针将通过以下方式推送到堆栈:
pool::get<T>().push(ptr);
  • 所以,我重新定义了这个列表的第一点:当想要创建一个新的packet<T>*,并且其类型的池为空时,在堆中创建一个新的数据包。如果池不为空,我使用new的“就地”版本:
new (pool::get<T>().top()) T(args);
pool::get<T>().pop();

因此,在程序退出时委托销毁,并且所有创建的内存都可以重复使用。

足够的解释!!

我的问题是:我需要任何其他类型为“user_t”的静态对象(实际上,不同类型的不同对象继承shared_obj),但它们中的任何一个都会产生内存泄漏,我的原因如下:

  • 在创建关联池之前创建静态对象,因为每个类型的packet_pool.get<T>()的定义在定义之后被实例化:模板定义在第一个使用指针中实例化为具体类型,而不是模板的写入位置。因此,我的文件中的词法顺序与我翻译单元中的定义顺序不同。
  • 因此,我的静态对象在其关联的池之后被破坏,因为静态对象按其构造的逆序删除,并且与其翻译单元的定义顺序一致。
  • 当破坏静态对象时,其关联的计数器达到0并尝试将其推入被破坏的池中。这引发了崩溃。

我的疑问终于如下:

  • 翻译单元中实例化模板功能的具体“定义顺序”是什么?我的假设是否正确?

这是一个平行的问题:

  • 问题是否也与池是本地静态函数或“get”函数本身内联(因为它是在其类中定义的函数)这一事实有关?我的意思是,每个“池”(每个堆栈)是否都有内部链接,并且我在不同的翻译单元中对同一类型有不同的pools吗?

0 个答案:

没有答案