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)

Was it helpful?

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

http://www.cplusplus.com/forum/general/14659/

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top