在编写对大型代码库的测试和分析过程中,我必须用自己的方法替换成千上万的对alloca()的调用。在我的目标平台上,如果数字为零,则alloca()失败,因此我们想断言是这种情况。我们还希望提供一个单一调用的对齐版本。但是,alloca()具有与范围相关的特定生存期,因此尽管我想写
void * CheckAndAllocate( size_t sizeInBytes )
{
assert( sizeInBytes > 0 );
return alloca(p); // not safe; allocation goes out of scope on return
}
void * p = CheckAndAllocate( sizeInBytes );
显然,这不是一个选择,因为alloca()不会超过CheckAndAllocate()。
为了解决这个问题,我使用一个临时的方法编写了这个替代方法:
struct CheckSize
{
inline CheckSize( size_t size ) { assert( size > 0 ); }
inline void * operator=(void* other) { return other );
}
#define my_alloca(size) CheckSize(size) = alloca(size)
void foo(size_t size)
{
void * p = my_alloca(size);
// becomes
void * p = CheckSize(size) = alloca(size);
// ... use p locally for work
}
此外,我还将对齐版本定义为:
struct CheckSizeAndAlign
{
size_t _align;
inline CheckSizeAndAlign( size_t size, size_t align ) : _align(align) { assert( size > 0 ); }
inline void * operator=(void* other) { return AlignUp(other, _align ); }
#define my_alloca_aligned( size, align ) CheckSizeAndAlign(size, align ) = alloca(size + align)
void foo(size_t size, size_t alignment)
{
void * p = my_alloca_aligned( size, alignment);
// becomes
void * p = CheckSizeAndAlign( size, alignment) = alloca( size + alignment )
// ... use p locally for work
}
我的问题是-鉴于alloca返回的值正在传递临时值,是否由于某种范围而违反了alloca的分配?
我认识到alloca周围存在陷阱,可以使用多种解决方案来解决此问题,但是我希望将这些更改注入代码库而无需更改其他任何内容,而只是添加一些诊断程序。
我也只是对此特定模式感到好奇。
这是MSVC2019,CLANG和利基实时系统编译器。
我建议添加一个辅助函数来执行您的assert
,调用alloca
,并将分配的内存传递给回调。这是我实现的第一步:
#include <alloca.h>
#include <cassert>
#include <iostream>
#include <utility>
namespace {
template <typename FN, typename ...ARGS>
auto alloc_helper(std::size_t size, FN fn, ARGS && ...args) {
assert(size > 0);
auto p = ::alloca(size);
return fn(p, std::forward<ARGS>(args)...);
}
}
int main() {
auto weird_add = [](void * p, auto init, auto other) {
auto ip = reinterpret_cast<int *>(p);
*ip = init;
return *ip + other;
};
std::cout << alloc_helper(sizeof(int), weird_add, 10, 17) << '\n';
return 0;
}
此解决方案的优点是只键入一次大小,再加上alloca
返回的指针的作用域恰好是您要使用的大小;除非回调return
是它(您可以在assert
上做,但会更难看)。您可以使其他辅助函数使用其他非动态分配(例如,您在注释中提到了alloca_aligned
)。