What alignment guarantees can I expect for arrays in a struct?
Question
I've got a lightweight templated class that contains a couple of member objects that are very rarely used, and so I'd like to avoid calling their constructors and destructors except in the rare cases when I actually use them.
To do that, I "declare" them in my class like this:
template <class K, class V> class MyClass
{
public:
MyClass() : wereConstructorsCalled(false) {/* empty */}
~MyClass() {if (wereConstructorsCalled) MyCallPlacementDestructorsFunc();}
[...]
private:
bool wereConstructorsCalled;
mutable char keyBuf[sizeof(K)];
mutable char valBuf[sizeof(V)];
};
... and then I use placement new and placement delete to set up and tear down the objects only when I actually need to do so.
Reading the C++ FAQ it said that when using placement new, I need to be careful that the placement is properly aligned, or I would run into trouble.
My question is, will the keyBuf and valBuf arrays be properly aligned in all cases, or is there some extra step I need to take to make sure they will be aligned properly? (if so, a non-platform-dependent step would be preferable)
Solution
There's no guarantee that you'll get the appropriate alignment. Arrays are in general only guaranteed to be aligned for the member type. A char
array is aligned for storage of char
.
The one exception is that char
and unsigned char
arrays allocated with new
are given maximum alignment, so that you can store arbitrary types into them. But this guarantee doesn't apply in your case as you're avoiding heap allocation.
TR1 and C++0x add some very helpful types though:
std::alignment_of
and std::aligned_storage
together give you a portable (and functioning) answer.
std::alignment_of<T>::value
gives you the alignment required for a type T
. std::aligned_storage<A, S>::type
gives you a POD type with alignment A
and size S
. That means that you can safely write your object into a variable of type std::aligned_storage<A, S>::type
.
(In TR1, the namespace is std::tr1
, rather than just std
)
OTHER TIPS
May I ask why you want to place them into a char buffer? Why not just create pointer objects of K and V then instantiate it when you need it.
Maybe I didn't understand your question, but can't you just do char *keyBuf[..size..];
, set it initially to NULL (not allocated) and allocate it the first time you need it?
What you're trying to do with placement new seems risky business and bad coding style.
Anyway, code alignment is implementation dependent.
If you want to change code alignment use pragma pack
#pragma pack(push,x)
// class code here
#pragma pack(pop) // to restore original pack value
if x is 1, there will be no padding between your elements.
Heres a link to read
I found this answer posted by SiCrane at http://www.gamedev.net/community/forums/topic.asp?topic_id=455233 :
However, for static allocations, it's less wasteful to declare the memory block in a union with other types. Then the memory block will be guaranteed to be aligned to the alignment of the most restrictive type in the union. It's still pretty ugly either way.
Sounds like a union might do the trick!
I recommend that you look at the boost::optional
template. It does what you need, even if you can't use it you should probably look at its implementation.
It uses alignment_of
and type_with_alignment
for its alignment calculations and guarantees.
To make a very very long story very very short this isn't going to help your performance any and will cause lots of headaches and it won't be long before you get sucked into writing your own memory managemer.
Placement new is fine for a POD (but won't save you anything) but if you have a constructor at all then it's not going to work at all.
You also can't depend on the value of your boolean variable if you use placement new.
Placement new has uses but not really for this.