提问人:himynameisjm 提问时间:9/14/2022 更新时间:9/14/2022 访问量:77
在函数作用域内使用 N size_t参数初始化堆栈上的数组时可能会出现问题?
Problems that may arise when initializing arrays on stack inside a function scope with an N size_t parameter?
问:
例如,假设我有一个函数,它接受一些参数和 a 来初始化函数内堆栈上的数组。size_t length
考虑到以下几点:
- 严格来说,只能在 1 到 30 的范围内(不允许使用固定的最大缓冲区长度 30)。
length
- only 保留在函数内部,仅用于计算结果。
array
int foo(/*some argument, ..., ... */ size_t length) {
uint64_t array[length];
int some_result = 0;
// some code that uses the array to compute something ...
return some_result;
}
在正常情况下,我会为此使用 ,或函数,但是......我正在尝试优化,因为该函数在程序的整个生命周期中被反复调用,使堆分配产生很大的开销。std::vector
new
*alloc
最初在堆栈上使用固定大小的数组是我提出的解决方案,但是由于某些原因,我无法做到这一点,因为这是不礼貌的。
无论如何,我想知道我是否可以摆脱这种方法而不会在未来遇到任何问题?
答:
1赞
selbie
9/14/2022
#1
在极少数情况下,我使用大型固定大小的临时缓冲区进行了一些图像处理,或者只是想避免冗余分配/空闲调用的运行时,我创建了自己的堆。
对于小额分配来说,这没有多大意义,你可以只使用堆栈,但你表示你的教练说不要这样做。所以你可以尝试这样的事情:
template<typename T>
struct ArrayHeap {
unordered_map<size_t, list<shared_ptr<T[]>>> available;
unordered_map<uint64_t*, pair<size_t, shared_ptr<T[]>>> inuse;
T* Allocate(size_t length) {
auto &l = available[length];
shared_ptr<T[]> ptr;
if (l.size() == 0) {
ptr.reset(new T[length]);
} else {
ptr = l.front();
l.pop_front();
}
inuse[ptr.get()] = {length, ptr};
return ptr.get();
}
void Deallocate(T* allocation) {
auto itor = inuse.find(allocation);
if (itor == inuse.end()) {
// assert
} else {
auto &p = itor->second;
size_t length = p.first;
shared_ptr<T[]> ptr = p.second;
inuse.erase(allocation);
// optional - you can choose not to push the pointer back onto the available list
// if you have some criteria by which you want to reduce memory usage
available[length].push_back(ptr);
}
}
};
在上面的代码中,您可以使用特定长度的缓冲区。第一次为给定的长度值调用时,将产生分配“new”的开销。但是当缓冲区返回到堆时,对相同长度的缓冲区进行第二次分配时,它会很快。Allocate
那么你的函数可以这样实现:
ArrayHeap<uint64_t> global_heap;
int foo(/*some argument, ..., ... */ size_t length) {
uint64_t* array = global_heap.Allocate(length);
int some_result = 0;
// some code that uses the array to compute something ...
global_heap.Deallocate(array);
return some_result;
}
1赞
Outtruder
9/14/2022
#2
就我个人而言,我会在堆栈上使用固定大小的数组,但如果有理由禁止它,请检查是否有任何针对 alloca() 方法的数组。
人 3 阿洛卡
评论
static std::vector<uint64_t> array; array.resize(length);