假设我正在编写一个简单的缓冲区类。这个缓冲区将作为标准 C 对象数组的简单包装器,并向后兼容现有函数,以便使用简单数组作为输入。
这里的目标是使此缓冲区在速度和内存使用方面都高效。由于堆栈分配始终比堆快,因此我想在堆栈上分配一切到一定阈值,如果它增长得更大,则重新在堆上分配。如何高效地实现这一点?
我进行了研究,显然 std::string 做了类似的事情。我只是不确定怎么做。我遇到的最接近的解决方案是以下伪代码(未编译):
正如您所看到的,当缓冲区增长超过MinSize时,_stack只是浪费空间。另外,如果Buffer足够大,则push和pop可能特别昂贵。另一个解决方案是始终在堆栈上保留前几个元素,并将溢出放在堆上。但这意味着缓冲区无法“转换”为简单的数组。
有更好的解决方案吗?如果在std :: string中完成此操作,是否有人指出如何或提供一些资源?
这里的目标是使此缓冲区在速度和内存使用方面都高效。由于堆栈分配始终比堆快,因此我想在堆栈上分配一切到一定阈值,如果它增长得更大,则重新在堆上分配。如何高效地实现这一点?
我进行了研究,显然 std::string 做了类似的事情。我只是不确定怎么做。我遇到的最接近的解决方案是以下伪代码(未编译):
template <typename T, int MinSize>
class Buffer
{
public:
void Push(const T& t)
{
++_size;
if (_size > MinSize && _heap == NULL)
{
// allocate _heap and copy contents from stack
// _stack is unused and wasted memory
}
else if (_heap != NULL)
{
// we already allocated _heap, append to it, re-allocate if needed
}
else
{
// still got room on stack, append to _stack
}
}
void Pop()
{
--_size;
if (_size <= MinSize && _heap != NULL)
{
// no need for _heap anymore
// copy values to _stack, de-allocate _heap
}
else if (_heap != NULL)
{
// pop from heap
}
else
{
// pop from stack
}
}
private:
T _stack[MinSize];
T* _heap;
int _size;
};
正如您所看到的,当缓冲区增长超过MinSize时,_stack只是浪费空间。另外,如果Buffer足够大,则push和pop可能特别昂贵。另一个解决方案是始终在堆栈上保留前几个元素,并将溢出放在堆上。但这意味着缓冲区无法“转换”为简单的数组。
有更好的解决方案吗?如果在std :: string中完成此操作,是否有人指出如何或提供一些资源?
std::string
有一个指针,它动态分配内存。实际上,栈上没有任何数据;所有数据都在堆上。坦白地说,我不确定为什么你不想一开始就把它放在堆上。当大小接近栈的极限时,如果发生其他事情导致栈溢出会怎样呢? - chrisMinSize
很小,那么栈溢出的可能性会很小(哈!)(除非对象真的很大,但这不应该是情况)。如果小缓冲区可以在堆栈内存上工作,那么将会有性能提升。因此,我想知道是否可能同时拥有两全其美的效果。 - Zeenobitminsize/sizeof T
作为数组大小,这样在栈使用方面更安全。对于动态数组,我会使用std::vector<T>
。 - PiotrNycz