Re: Prevent object from existing on the heap
On Mon, 14 Sep 2009 15:26:22 CST, crobi <blbounnejapny@hotmail.com>
wrote:
The real problem I am trying to solve is prevent objects with
__declspec(align) not being aligned. __declspec(align) tells the
Microsoft compiler the base address of an object should be aligned,
but it works only for objects created on the stack, ...
__declspec(align(#)) actually pads the size of the object, rounding up
to the next multiple of # bytes. By itself it does not guarantee
address alignment.
Alignment declarations are not used by the standard allocators. For
aligned heap allocations in VC++ you have to call _aligned_malloc:
<type> *p = _aligned_malloc( sizeof(<type>), _alignof(<type>) );
This only applies to heap objects ... aligning objects or arrays on
the stack, if necessary, must be done manually.
... since when calling standard new there is no way to specify the
alignment.
I know this is a Microsoft extension, but there exist equivalent
directives with the same problem in other compilers, so I hope to find
a moderately portable way to prevent or detect the problem.
I know there are methods to prevent operator new from being called for
a class, but I have to also prevent operator new from being called for
any class that contains a member variable of my class, since otherwise
that member would not be aligned.
You can redefine ::new as well as class new. Just create your own
version that does what you want.
So, my goal is to get a compiler error for any of the lines marked as
NOT OK in the following example. I would prefer a compiler error to a
runtime exception, because I potentially create millions of such
objects per second (on the stack with empty constructors, so it does
not take any time now).
Also, testing for (this % 16 == 0) does not detect the cases where the
object was correctly aligned by coincidence. And again, I know my real
problem is compiler and platform specific, but I want to find a
standard c++ way to detect it.
__declspec(align(16))
class MyClass
{
public:
MyClass()
{
assert(reinterpret_cast<int>(this) % 16 == 0);
}
};
// Lots of such container classes
class MyContainer
{
MyClass member;
};
void test()
{
MyClass x; // OK
MyClass* pX1 = new MyClass(); // NOT OK
MyClass* pX2 = &x; // OK
MyContainer y; // OK
MyContainer* pY = new MyContainer(); // NOT OK
}
Thanks for any ideas!
The only semi-portable way to create aligned locals is to redefine
class new to use alloca (_alloca in VC++) to allocate a properly
aligned stack buffer. Something like:
__declspec(align(128))
class MyStackLocalClass
{
public:
inline void* operator new( size_t size )
{
return _alloca( size + ((size_t)_alloca(0) % size) );
};
inline void* operator new[]( size_t size )
{
return _alloca( size + ((size_t)_alloca(0) % size) );
}
};
The functions must be inlined and you can't use any local variables
unless you factor their sizes into the padding calculation. alloca(0)
returns the current stack location (this code presumes the stack grows
downward).
NB: This will *NOT* work properly in debug mode because the inline
directive is ignored. In debug mode the call to new() creates a new
stack frame so the newly allocated object buffer disappears
immediately when new() returns.
Replacing class new still does not work for objects passed by value as
arguments ... they are constructed wherever the top-of-stack happens
to be at the time. Passing an aligned object by value is an error in
VC++ (at least in VC++03 and later) ... probably also in G++ but I
haven't tested it.
George
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]