首先,对不起我的英语:
我设计了一个小库来管理我的程序使用的内存。主要是实现了一种具有内存管理目的的共享对象。我有以下类(我省略了其他不需要的成员和函数来解释我的问题):
- 一个名为的参数结构
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
使用静态参数函数(当然还有其他代码)调用的类,返回对 a 的引用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>
复制 a 时,其关联数据包的计数器都会递增。 - 每次
shared_obj<T>
调用 a 的析构函数时,其关联数据包的计数器都会递减。 - 如果其关联数据包的计数器达到 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
我的意思是,每个“池”(每个堆栈)是否具有内部链接,并且对于不同翻译单元中的相同类型,我是否有不同的链接?