Allocation schema w.r.t. padding and alignment...

S

SenderX

I am thinking of porting a library from C to C++, and was tinkering with
ways to ensure proper struct padding and alignment. The library is very
hardware specific, and will simply crash and/or perform bad if the memory
some of its algos use is not properly padded and aligned. So I had to come
up with a way to create several objects of the same class that have
different alignment and padding...

Consider my temporary solution, using placement new and templates:


Example.cpp
( compiles with GCC and MSVC++6.0 )
-----------------

// C++ code created by C programmer!

#include <iostream>
#include <cassert>
#include <cstddef>
#include <new>


#define AC_CACHE_LINE 128
#define AC_ALGO1_ALIGN ( AC_CACHE_LINE / 2 )
#define AC_ALGO2_ALIGN ( AC_CACHE_LINE * 2 )


template< size_t T_Align >
struct TExampleImpl_Padded
{
// snip

int m_iExampleState;

// Is this legal!?! Works for GCC... humm
char PAD1[T_Align - sizeof( int )];
};


struct SExampleImpl
{
int m_iExampleState;
};


template< typename T_Impl, size_t T_Align /* snip */ >
class TExample
{

public:

TExample() : m_pImpl( 0 ), m_pImplMem( 0 )
{
// Assert
if ( ! T_Align ||
T_Align != 1 && ( ((ptrdiff_t)m_pImpl) % sizeof( size_t ) ) )
{
throw;
}

// Alloc and align
m_pImplMem = ::eek:perator new( sizeof( T_Impl ) + ( T_Align - 1 ) );

m_pImpl = new ( (void*)(( (((ptrdiff_t)m_pImplMem) + (T_Align - 1))
& -(T_Align) )) ) T_Impl;

// Assert
if ( T_Align != 1 && ( ((ptrdiff_t)m_pImpl) % T_Align ) )
{
m_pImpl->~T_Impl();
::eek:perator delete( m_pImplMem );

throw;
}

std::cout << m_pImpl << "::sizeof - " << sizeof( *m_pImpl ) <<
std::endl;

// Init impl
m_pImpl->m_iExampleState = 0;
}

~TExample()
{
assert( m_pImpl && m_pImplMem );

// Dtor, placement new...
m_pImpl->~T_Impl();
::eek:perator delete( m_pImplMem );
}


public:


// snip


private:

T_Impl *m_pImpl;
void *m_pImplMem;
};


// Now I can create a number of different padding and alignments

typedef TExample< TExampleImpl_Padded< AC_CACHE_LINE >, AC_CACHE_LINE >
CExample;
typedef TExample< TExampleImpl_Padded< AC_ALGO1_ALIGN >, AC_ALGO1_ALIGN >
CExampleAlgo1;
typedef TExample< TExampleImpl_Padded< AC_ALGO2_ALIGN >, AC_ALGO2_ALIGN >
CExampleAlgo2;
typedef TExample< SExampleImpl, 1 > CLwExample;




int main()
{
CExample s;
CExampleAlgo1 sa1;
CExampleAlgo2 sa2;
CLwExample lws;

return 0;
}


As you can see, this provides the solution I want, and passes all of the
library's tests, but...

Is this a non-portable crappy solution? If so, got anything better? I'm not
that good at C++, I'm a C guy...

;)

Thank you.
 
S

SenderX

public:
TExample() : m_pImpl( 0 ), m_pImplMem( 0 )
{


DOH!

***************
// Assert
if ( ! T_Align ||
T_Align != 1 && ( ((ptrdiff_t)m_pImpl) % sizeof( size_t ) ) )
{
throw;
}
**************

This was not suppose to be pasted in the example!

Sorry.

:O
 
P

perry

you know, i use to be such a fan of c++

i think it's the templates that get me down the most...

and to think they've actually brought these over to Java now...

- perry
I am thinking of porting a library from C to C++, and was tinkering with
ways to ensure proper struct padding and alignment. The library is very
hardware specific, and will simply crash and/or perform bad if the memory
some of its algos use is not properly padded and aligned. So I had to come
up with a way to create several objects of the same class that have
different alignment and padding...

Consider my temporary solution, using placement new and templates:


Example.cpp
( compiles with GCC and MSVC++6.0 )
-----------------

// C++ code created by C programmer!

#include <iostream>
#include <cassert>
#include <cstddef>
#include <new>


#define AC_CACHE_LINE 128
#define AC_ALGO1_ALIGN ( AC_CACHE_LINE / 2 )
#define AC_ALGO2_ALIGN ( AC_CACHE_LINE * 2 )


template< size_t T_Align >
struct TExampleImpl_Padded
{
// snip

int m_iExampleState;

// Is this legal!?! Works for GCC... humm
char PAD1[T_Align - sizeof( int )];
};


struct SExampleImpl
{
int m_iExampleState;
};


template< typename T_Impl, size_t T_Align /* snip */ >
class TExample
{

public:

TExample() : m_pImpl( 0 ), m_pImplMem( 0 )
{
// Assert
if ( ! T_Align ||
T_Align != 1 && ( ((ptrdiff_t)m_pImpl) % sizeof( size_t ) ) )
{
throw;
}

// Alloc and align
m_pImplMem = ::eek:perator new( sizeof( T_Impl ) + ( T_Align - 1 ) );

m_pImpl = new ( (void*)(( (((ptrdiff_t)m_pImplMem) + (T_Align - 1))
& -(T_Align) )) ) T_Impl;

// Assert
if ( T_Align != 1 && ( ((ptrdiff_t)m_pImpl) % T_Align ) )
{
m_pImpl->~T_Impl();
::eek:perator delete( m_pImplMem );

throw;
}

std::cout << m_pImpl << "::sizeof - " << sizeof( *m_pImpl ) <<
std::endl;

// Init impl
m_pImpl->m_iExampleState = 0;
}

~TExample()
{
assert( m_pImpl && m_pImplMem );

// Dtor, placement new...
m_pImpl->~T_Impl();
::eek:perator delete( m_pImplMem );
}


public:


// snip


private:

T_Impl *m_pImpl;
void *m_pImplMem;
};


// Now I can create a number of different padding and alignments

typedef TExample< TExampleImpl_Padded< AC_CACHE_LINE >, AC_CACHE_LINE >
CExample;
typedef TExample< TExampleImpl_Padded< AC_ALGO1_ALIGN >, AC_ALGO1_ALIGN >
CExampleAlgo1;
typedef TExample< TExampleImpl_Padded< AC_ALGO2_ALIGN >, AC_ALGO2_ALIGN >
CExampleAlgo2;
typedef TExample< SExampleImpl, 1 > CLwExample;




int main()
{
CExample s;
CExampleAlgo1 sa1;
CExampleAlgo2 sa2;
CLwExample lws;

return 0;
}


As you can see, this provides the solution I want, and passes all of the
library's tests, but...

Is this a non-portable crappy solution? If so, got anything better? I'm not
that good at C++, I'm a C guy...

;)

Thank you.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top