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 = :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();
: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();
: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.
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 = :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();
: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();
: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.