在堆栈上分配任意常量大小的结构
Allocating structs of arbitrary constant size on the stack
我已经编写了一个小型的插件服务器。插件是使用.so
共享对象来实现的;服务器";通过对CCD_ 2(报头<dlfcn.h>
(的调用。
所有共享对象插件都有相同的接口:
extern "C" void* do_something() {
return SharedAllocator<T>{}.allocate(...); // new T
}
extern "C" size_t id = ...; // unique
- 基本上,
do_something
返回一个指向堆内存的指针,调用方应释放该指针 - CCD_ 5只是每个CCD_ 6唯一的标识符
- CCD_ 7是每个CCD_。其中一些具有相同的返回类型,而另一些则没有。这里的重点是,
sizeof(T)
是.so
特有的
服务器负责动态加载和读取.so
二进制文件的符号。所有.so
插件都可以通过服务器二进制文件中定义的方法do_something_proxy
相互调用,该方法充当调用方和被调用方之间的粘合剂:
extern "C" void* do_something_proxy(size_t id) {
// find the requested handle
auto handle = some_so_map.find(id)->second;
// call the handle's `do_something`
void* something_done = handle.do_something();
// forward the result
return something_done;
}
为了稍微简化一下,假设some_so_map
是一个普通的std::unordered_map<size_t, so_handle_t>
,在执行代理时使用对dlopen
的一组调用填充。
我的问题是do_something_proxy
的每个调用者在编译时都知道T
。正如我前面所说的,T
可能因呼叫站点而异;但是CCD_ 20对于任意呼叫站点从不更改。
作为参考,以下是所有调用方使用的定义:
template <typename T, size_t id>
T* typed_do_soemthing_proxy() {
// simple cast of the proxy
return reinterpret_cast<T*>(do_soemthing_proxy(id));
}
换句话说,对于某个任意插件dlopen
2,do_something_proxy
总是具有相同的返回类型。
如果不是因为代理,我可以只模板do_soemthing_proxy
并传递T
或带有sizeof(T) == N
的std::array<int8_t, N>
,并且在调用do_something_proxy
时为确保T
不被切片而分配的不必要内存可以移动到堆栈中。然而,代理在编译时不能知道所有可能的返回类型,并导出无数版本的do_something_proxy
。
所以我的问题是,do_soemthing_proxy
有没有办法在其堆栈上分配T
的有效大小(即使用alloca
或其他形式的堆栈分配(?
据我所知,alloca
在这里似乎不起作用,因为do_soemthing_proxy
只能从所请求插件的do_something
函数中接收一个值。do_soemthing_proxy
将同时接收要分配的大小和要复制到分配的存储器的字节。如果只有CCD_;压扁的";介于。。。
我知道我可以使用std::array<int8_t, N>
在堆栈上分配固定数量的内存,CCD_38的值为256甚至1024。但是,这个解决方案有点脏。它不必要地将数据从一个堆栈帧复制到另一个堆栈框架,并限制插件可以返回的数据量。最重要的是,(虽然我还没有对这个解决方案进行基准测试(除非编译器可以消除跨动态边界的复制,否则我认为复制1024字节比复制sizeof(std::string)
字节要多得多。
在理想的情况下,我认为do_soemthing_proxy
应该返回一个使用RAII处理此问题的结构。一个const std::any
,如果您愿意的话,它是堆栈分配的。这可能吗?
如果这在c++中根本不可能,那么在汇编中是否可以以可移植的方式实现这种行为,即手动劫持堆栈或基指针?
谢谢。
实际上,我刚刚找到了一个解决方案。它可以归结为反转用于分配T
的存储器位置的传递方向。
do_soemthing_proxy
有没有办法在其堆栈上分配T
的有效大小?
也许吧。但代码实际需要的是在调用者的位置分配T
的有效大小,而不是在代理内部。由于调用者知道sizeof(T)
,您所要做的就是在调用do_something
之前,在调用者的堆栈上为T
分配空间,然后在调用时将分配的缓冲区的地址传递给id
0:
对于呼叫者:
template <typename T, size_t id>
T typed_do_something_proxy() {
std::aligned_storage_t<sizeof(T), alignof(T)> return_buffer;
do_something_proxy(id, &return_buffer);
return *std::launder(reinterpret_cast<T*>(&return_buffer));
}
代理:
extern "C" void do_something_proxy(size_t id, void* return_buffer) {
auto handle = some_so_map.find(id)->second;
handle.do_something(return_buffer);
}
对于被叫
extern "C" void do_something(void* return_buffer) {
new(return_buffer) T(...); // placement new
}
- 为什么"具有常量成员的结构"类型的指针不能指向"具有非常量成员的结构"?
- 调用 cout 时如何在结构中输出常量文本?
- 返回对常量结构(指针类型)成员的引用:明显的左值到右值转换
- 将结构C++成员从非常量转换为常量
- 列出常量和数组结构字段的初始化
- 如何初始化具有常量变量的结构数组
- c++ 是否提供了一种使整个结构常量(不可修改)的方法?
- ARM C++编译器不会编译具有可变常量成员的结构
- 为什么常量静态变量应该在结构中初始化?
- CPP/C 中的常量用法和结构构造函数中的澄清
- 常量结构的指针成员
- 结构中的常量成员即使在初始化后也返回 0
- 结构初始化中的常量正确性
- 如何将常量中的值设置为结构 c++ 中
- 如何在C++中声明静态常量结构
- 结构内工会的常量成员的问题
- 如何在 C++11 中创建结构的编译时常量实例
- C++常量结构成员初始化
- C++:结构、运算符"new"和常量
- 使结构体在 C 中常量