c++ - 使用赋值运算符检查和对齐 alloca() 的临时生命周期
问题描述
在编写大型代码库的一些测试和分析过程中,我不得不用自己的方法替换对 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
在评论中提到)。
推荐阅读
- javascript - 如何在我的 Redux 应用程序中实现这些备注?
- javascript - 获取已更改的属性列表?
- java - 执行删除语句时休眠抛出ConstraintViolationException
- javascript - 使用 React Hooks 和 Redux 重新渲染的次数过多
- android - 在 kotlin 中从非 UI 线程编辑 livedata
- c++ - 具有从“NameBase”类到模板“Name”类的相互继承的 C++ 习语(或模式)
- function - 我正在使用 fullpage.js 并想隐藏小屏幕的导航选项(最大宽度:700px)
- c# - 如何在 C# 中的字符串中找到某个字母?
- ruby-on-rails - Rails ActiveStorage:如何避免为每张图片重定向一次?
- python - Matlab 到 Python 的正确翻译(CID 距离)