好的,首先,性能在这里是最重要的,所以我怀疑地图是否有效。我有一个结构列表(大约16个),如
struct A { ... };
struct B { ... };
...
每个都不同,每个都有不同的大小。
我想知道我们可以采取哪种优雅的方式:
char BufferA[sizeof(struct A)];
char BufferB[sizeof(struct B)];
然后编写一些方法或映射来返回BufferA如果你正在使用struct A.速度绝对是最重要的,我想使用模板会有所帮助,但我不确定它是否整个事情都可以被模板化。
更新***对不清楚,缓冲区都已预先分配。我只需要一种非常快速的方法来获得给定结构类型的正确缓冲区。
更新2 ***很抱歉没有指定,对齐是一个重要的特性,我实际上用#pragma pack(push,1)对每个结构进行字节对齐
答案 0 :(得分:4)
template<typename X>
struct Buffer
{
static char *ptr()
{
// Note if no alignment is needed for your use then
// just a simple "static char buf[sizeof(X)]; return buf;"
// would be sufficient instead of the following.
union Aligner {
X x;
char buf[sizeof(X)];
};
static Aligner a;
return a.buf;
}
};
struct B
{
int x, y, z;
};
void foo()
{
Buffer<B>::ptr()[2] = 12;
}
使用g++ -O2
,上面的代码只会在foo
中生成一个固定的内存写入操作。
.globl _Z3foov
.type _Z3foov, @function
_Z3foov:
.LFB1:
.cfi_startproc
.cfi_personality 0x0,__gxx_personality_v0
pushl %ebp
.cfi_def_cfa_offset 8
movl %esp, %ebp
.cfi_offset 5, -8
.cfi_def_cfa_register 5
movb $12, _ZZN6BufferI1BE3ptrEvE1a+2 <=== this is the assignment
popl %ebp
ret
.cfi_endproc
答案 1 :(得分:1)
char BufferA[sizeof(struct A)];
无法保证自动排列数组正确对齐。 (运算符new(some_size)和new char [some_size]保证对齐,但不是这种情况。)但是,您可以在char数组上使用特定于编译器的对齐。
我想使用模板会有所帮助,但我不确定整个事情是否可以模板化。 ...我只需要一种非常快速的方法来获得给定结构类型的正确缓冲区。
由于这是基于类型的,因此模板是正确的方法。
template<class T>
struct Buffer {
static char buffer[sizeof(T)] __attribute__((aligned)); // gcc's syntax
};
更方便地访问它,而不是Buffer&lt; A&gt; :: buffer:
template<class T>
inline
char* get_buffer() {
return Buffer<T>::buffer;
}
void construct_example() {
new (get_buffer<A>()) A();
// same as:
new (Buffer<A>::buffer) A();
}
这只允许每个结构类型一个缓冲区 - 这可能是一个问题 - 但它似乎是你期望和想要的。
答案 2 :(得分:0)
您可以编写具有数字模板参数的模板类,以及缓冲区的静态成员。这样的事情(未经测试):
template <size_t S>
class GlobalBuffer
{
static char Buffer[S];
};
获取具有特定大小的结构的缓冲区现在可以这样写:
GlobalBuffer<sizeof(struct A)>::Buffer;
答案 3 :(得分:0)
如果您从中调用此代码的代码实际上具有类型A
或其他类型的变量(而不是某种运行时切换),那么您可以在调用时将其用作模板参数返回缓冲区的函数。这看起来像这样:
template <typename T>
char *makebuffer()
{
return malloc(sizeof(T));
}
然后,在您的代码中,您编写makebuffer<A>()
,它将分配一个正确大小的缓冲区并将其返回。
答案 4 :(得分:0)
建议:改变设计。让结构返回指向其预期缓冲区的指针。
根据您的帖子,每个结构都有一个与之关联的缓冲区。这可以翻译为该结构具有将返回相关缓冲区的方法。
这样的事情:
struct A
{
char * get_buffer(void) const;
};
在实施文件中:
static char Buffer_A; // Static to keep it private to this translation unit.
char * A::get_buffer(void) const
{
return Buffer_A;
};
就执行而言,这是非常有效的。它也导致了通用性。您可以将纯虚拟抽象方法放在父类中以返回缓冲区,从而处理指向其他函数中父类的指针或引用。
注意:上面的实现使用在类外声明的自动变量。在结构内声明的变量可以放在堆栈上,它可能比在类外部声明的变量具有更小的限制。也可以使用动态内存声明更大的缓冲区。有关内存容量限制,请参阅编译器的文档。
答案 5 :(得分:0)
这是字段剩下的东西,使用boost融合容器,特别是map。
#include <iostream>
#include <boost/fusion/container/map.hpp>
#include <boost/fusion/sequence/intrinsic/at_key.hpp>
#include <boost/array.hpp>
struct A{int a, b, c;};
struct B{double a, b, c;};
struct C{bool a, b, c; };
template <class T>
struct data
{
data() : buffer() {}
size_t size() const { return buffer.size(); }
boost::array<char, sizeof(T)> buffer; // assuming no alignment issues!
};
int main(void)
{
boost::fusion::map<boost::fusion::pair<A, data<A> >,
boost::fusion::pair<B, data<B> >,
boost::fusion::pair<C, data<C> >
> buffer_holder;
// to access
std::cout << boost::fusion::at_key<A>(buffer_holder).size() << std::endl; // returns reference to data<A>
return 0;
}
这里,每种类型的所有缓冲区都由一个组件拥有,并且每个缓冲区都是正确构造的,并且可以由data
包装器进行管理(如果您处于多线程环境中,则非常有用)。看起来不是静止...下行是你可以使用的模板参数数量有限,你可以用编译器标志来增加它(之前我用了30个)。
答案 6 :(得分:0)
尝试使用联合:在编译时解析,您可以在代码中稍作修改即可使用。
#include <iostream>
typedef struct A_
{
int kk;
long long pp;
};
//
// with this kind of struct, you have instant access to A contens without memory malllocs, memory leaks,
// you can use in multithread environments, ......
// you don't need virtual tables and so on. You can inherit.......
// you don't spend more memory yhan really necesary
// you don't spend time in functions calling ...
//
typedef struct A
{
union
{
A_ a;
char buffer[sizeof(A_)];
};
};
int main(int argc, char **argv)
{
A a;
// we fill the struct information
a.a.kk = 12;
a.a.pp = 99991829;
A b;
// we access to A buffer without problems
memcpy(&b, a.buffer, sizeof(b));
std::cout << "b.a.kk = " << b.a.kk << " b.a.pp = " << b.a.pp << std::endl;
}