C++ 我可以使用std::stack作为对象池容器吗?

C++ 我可以使用std::stack作为对象池容器吗?,c++,stl,memory-management,containers,C++,Stl,Memory Management,Containers,我需要创建一个对象池来消除动态分配。使用std::stack包含已分配对象的指针是否有效 我怀疑每次我将释放的对象推回堆栈时,都会动态分配一个新的堆栈元素。我说得对吗?我是否应该使用std::vector来确保没有分配新的内容?堆栈是否适合您的特定用途是我将不讨论的问题。现在,如果您关心分配的数量,那么std::stack的默认内部容器是std::deque。它不需要在每次推送中为堆栈分配新内存(只要它有空间),并且在分配时不需要像std::vector那样重新定位所有现有元素 您可以告诉堆栈使

我需要创建一个对象池来消除动态分配。使用std::stack包含已分配对象的指针是否有效


我怀疑每次我将释放的对象推回堆栈时,都会动态分配一个新的堆栈元素。我说得对吗?我是否应该使用std::vector来确保没有分配新的内容?

堆栈是否适合您的特定用途是我将不讨论的问题。现在,如果您关心分配的数量,那么std::stack的默认内部容器是std::deque。它不需要在每次推送中为堆栈分配新内存(只要它有空间),并且在分配时不需要像std::vector那样重新定位所有现有元素

您可以告诉堆栈使用std::vector作为具有第二个模板参数的基础容器:

std::stack< int, std::vector<int> > vector_stack;
std::stackvector\u stack;

指针的STL容器对它们指向的对象没有任何作用,这取决于您,因此您有责任不泄漏任何内存等。查看或尝试存储实际对象,从长远来看,您将省去麻烦

如果您想减少容器的动态分配量,并且大致知道需要存储多少对象,可以使用vector的“reserve()”方法,该方法将一次性预先分配您请求的内存

您还可以在构造函数中指定所需的记录数,但这种方式将为您创建x个对象,然后存储它们,这可能不是您想要的

如果出于某种技术原因,动态分配完全失效,您可能希望尝试使用作为分配器(您知道,如果不想使用默认分配器,您可以指定不同的std库内存分配器)


也就是说,当我测试它时,默认的总是更快,至少在g++中是这样,所以可能不值得这么做。确保您对其进行了概要分析,而不是假设您可以编写出标准委员会的代码

在自由活动期间做任何allocs都是错误的,因为没有任何保证。如果你必须做一个alloc来做一个自由和alloc抛出你把指针放在哪里?您可以安静地捕获异常并泄漏异常,也可以传播异常。传播异常意味着不能将使用
YourObject
的对象放入STL容器中。而泄漏就是泄漏。无论哪种情况,你都违反了规则

但是使用什么样的数据结构取决于对象生命周期控制习惯用法

习惯用法是一个对象池,用于工厂方法和freeInstance吗

 YourObject* pO = YourObject::getInstance(... reinitialize parameters ...);
 ......object public lifetime....
 pO->freeInstance();
或与特定于类的运算符new/operator delete(或分配器)一起使用的内存池

如果它是一个对象池,并且您对发布的代码和deque中对象*的使用向量的数量有一个概念,或者最好是一个循环缓冲区(因为deque没有保留,所以您必须在调试代码中添加它,因为动态自调整循环缓冲区正是您想要的),并保留近似的数量。在发布中分配后进先出,在调试中分配先进先出,这样您就可以在调试中拥有历史记录

在没有可用对象的路径中,请记住在动态创建对象之前在
YourObject*
collection上执行
reserve(nMade+1)

(这个保留的原因有两个。首先,它必须在
createInstance
时间完成。其次,它简化了代码。否则,您可能会在
freeInstance
中抛出std::badalloc,这可能使析构函数的保证难以保证。哎哟!例如,-Y类有一个
YourObject。)*你的对象*
做一个
自由实例
——如果你在创建时没有为
你的对象
*预留空间,你在
自由实例
时间哪里存储指针?如果你在
getInstance
中预留空间,那么你必须捕获std::badalloc对于保留,释放刚刚制作的
YourObject
,然后
重新播放

如果它是一个内存池,那么在内存块中,在发布时使用一个侵入性的单链表,在调试时使用双链表(我假设
sizeof(YourObject)>=2*sizeof(void*)
),顺便说一句,有很多内存池实现。再次在发布时分配LIFO,在调试时分配FIFO,这样您在调试时就有了历史记录

顺便说一句,如果你使用工厂习惯用法,不要跳过重载的getIntances()并添加reinit方法。这只是打开了省略reinit调用的可能性。getInstance方法是你的“构造函数”从某种意义上说,正是它们使对象达到了您想要的状态。请注意,在对象池的情况下,您需要一个freeInstance,它可能必须对对象执行“类似析构函数”的操作

在这种情况下,谈论“公共类不变量”和“私有类不变量”是有意义的-对象处于不稳定状态,在空闲池中,公共类不变量可能会得不到满足。就
YourObject
而言,这是一个
YourObject
,但所有公共类不变量都可能得不到满足。YourObject::getInstance的工作是获取一个实例并确保满足其公共不变量。freeInstance以一种互补的方式释放getInstance可能获得的资源,以确保满足的“公共类不变量”可以在自由列表上的对象“空闲时间”期间释放

发布的后进先出还具有缓存最后使用的对象/块的显著的好处,如果存在足够多的对象/块,则保证as FIFO不会缓存,如果
YourObject::operator new(size_t);
......object public lifetime....
delete pO;