问题
OK first and foremost, performance is most important here so I doubt a map would work. I have a list of structs (about 16 of them) like
struct A { ... };
struct B { ... };
...
each are different and each are of different sizes.
I'm wondering what elegant way we might be able to do something along the lines of:
char BufferA[sizeof(struct A)];
char BufferB[sizeof(struct B)];
then write some method or mapping to return BufferA if you are working with struct A. Speed is definitely the most important, I imagine using templates would help but I'm not sure it the whole thing can be templatized.
Update*** Sorry for not being clear, the buffers are all pre-allocated. I just need a very fast way to get the proper Buffer given a struct type.
Update 2*** Sorry for not specifying, alignment is an important trait here and I do in fact byte-align each struct with #pragma pack(push, 1)
回答1:
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;
}
With g++ -O2
the code above generates just a fixed memory write operation in 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
回答2:
char BufferA[sizeof(struct A)];
Auto char arrays are not guaranteed to be aligned correctly. (Alignment is guaranteed for operator new(some_size) and new char[some_size], but those are not this case.) However, you can use compiler-specific alignment on a char array.
I imagine using templates would help but I'm not sure it the whole thing can be templatized. … I just need a very fast way to get the proper Buffer given a struct type.
Since this is based on type, a template is the right way to go.
template<class T>
struct Buffer {
static char buffer[sizeof(T)] __attribute__((aligned)); // gcc's syntax
};
And to access it more conveniently, rather than Buffer<A>::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();
}
This only allows one buffer per struct type – and that's likely to be a problem – but it seems to be what you expect and want.
回答3:
You could write a template class having a numerical template parameter, and a static member for the buffer. Something like this (not tested):
template <size_t S>
class GlobalBuffer
{
static char Buffer[S];
};
Getting the buffer for a struct with a specific size can now be written like this:
GlobalBuffer<sizeof(struct A)>::Buffer;
回答4:
If the code that you're calling this from is something that literally has variables of type A
or whatever (rather than having some sort of runtime switch), then you can use that as a template parameter when calling the function that returns the buffer. That would look something like this:
template <typename T>
char *makebuffer()
{
return malloc(sizeof(T));
}
Then, in your code, you write makebuffer<A>()
and it will allocate a buffer of the correct size and return it.
回答5:
A suggestion: change in the design. Have the structures return a pointer to their prospective buffers.
According to your post, each structure has-a buffer associated with it. This can be translated as the structure has a method that will return an associated buffer.
Something like this:
struct A
{
char * get_buffer(void) const;
};
In the implementation file:
static char Buffer_A; // Static to keep it private to this translation unit.
char * A::get_buffer(void) const
{
return Buffer_A;
};
This is very efficient as far as execution goes. It also leads to genericity. You could put a pure virtual abstract method in a parent class for returning buffers, and thus deal with pointers or references to the parent class in your other functions.
Note: The implementation above uses an automatic variable declared outside the class. Variables declared inside a structure may be placed on the stack which may have smaller size restriction than a variable declared outside of the class. Larger buffers may also be declared using dynamic memory. See your compiler's documentation for memory capacity restrictions.
回答6:
Here is something left of field, use a boost fusion container, specifically, 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;
}
Here, all the buffers for each type is owned by a single component, and each buffer is properly constructed and can be managed by the data
wrapper (useful if you're in a multithreaded environment). Not a static in sight... Downside is that there is a limit to the number of template parameters you can use, you can increase this with a compiler flag (I've used up to 30 before).
回答7:
try to use unions: are resolved at compiling time and you can use with little modifications in your code.
#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;
}
来源:https://stackoverflow.com/questions/4880328/absolute-fastest-and-hopefully-elegant-way-to-return-a-certain-char-buffer-giv