I\'ve got some code that uses type-punning to avoid having to call a member \"object\"\'s constructor and destructor unless/until it\'s actually necessary to use the object.
I think the typedef
is confusing GCC. These sorts of attributes seem to work best when applied directly to variable definitions.
This version of your class works for me (GCC 4.6.0):
template<class T> class Lightweight
{
private:
// typedef T __attribute((__may_alias__)) T_may_alias;
public:
Lightweight() : _isObjectConstructed(false) {/* empty */}
~Lightweight()
{
// call object's destructor, only if we ever constructed it
if (_isObjectConstructed) {
T * __attribute__((__may_alias__)) p
= (reinterpret_cast<T *>(_optionalObject._buf));
p->~T();
}
}
void MethodThatGetsCalledOften()
{
// Imagine some useful code here
}
void MethodThatGetsCalledRarely()
{
T * __attribute__((__may_alias__)) p
= (reinterpret_cast<T *>(_optionalObject._buf));
if (_isObjectConstructed == false)
{
// demand-construct the heavy object, since we actually need to use it now
(void) new (p) T();
_isObjectConstructed = true;
}
p->DoSomething();
}
[etc.]
I would argue for having your containing class just contain a char array of sufficient size to contain your member "object" and then using placement new to initialize on top of the char array. That has the perk of being specification-compliant as well as cross-compiler. The only problem is that you have to know the size in chars of your member object, which may get you in trouble.
Is there a reason you can't have the member be a pointer and use new and delete?
What if you replace _isObjectConstructed
with a pointer to the object:
class Lightweight { public: Lightweight() : object(NULL) {/* empty */} ~Lightweight() { // call object's destructor, only if we ever constructed it if (object) object->~T(); } void MethodThatGetsCalledOften() { // Imagine some useful code here } void MethodThatGetsCalledRarely() { if (!object) { // demand-construct the heavy object, since we actually need to use it now object = new (_optionalObject._buf) T(); } object->DoSomething(); } private: union { char _buf[sizeof(T)]; unsigned long long _thisIsOnlyHereToForceEightByteAlignment; } _optionalObject; T *object; };
Note, no GCC extension, only pure C++ code.
Using a T*
instead of a bool
won't even make Lightweight
any bigger!