Sign in to follow this  
Nitage

byte arrays and allignment

Recommended Posts

I'm trying to create a class with an optional member variable. I want use these classes in a vector, first calling reserve so that no memory allocation takes place when I'm filling the vector. However, if I make the member variable optional by using a pointer, every time I construct one of the objects, I have to use dynamic allocation, which is what I wanted to avoid in the first place. So I came up with something that looks like this (where byte is a typedef for unsigned char): byte T_[sizeof(T)]; My question is this: How do I ensure that the byte array has the correct allignment for a T? I have been told that there is no portable way to do this - I'm using VC++7.1 and gcc4.

Share this post


Link to post
Share on other sites
For alignment I use something like:


#if USE_MSVC
// Pre-object alignment declaration.
#define ALGN __declspec(align(16))
// Post-object alignment declaration.
#define ALGNA
#elif USE_GCC
#define ALGN
#define ALGNA __attribute__ ((aligned(16)))
#endif
// Simple alignment declaration.
#define ALGN_D(x) ALGN x ALGNA

static ALGN_D( const int a ) = 5;

ALGN class A
{
// ...
} ALGNA;




Why do you want to hide the variable as a byte array? Not to call it's default constructor, maybe? If it's so important, why don't you try making a non-default constructor, of the potential member, that does nothing, then call it by default in your class, that has the member.

Also, you would have to provide proper allocation for your in-vector class, so that it is properly aligned itself.
/def

Share this post


Link to post
Share on other sites
Quote:
Original post by Nitage
My question is this: How do I ensure that the byte array has the correct allignment for a T? I have been told that there is no portable way to do this - I'm using VC++7.1 and gcc4.


as you say there's no portable 100% sure way of assuring that and afaik there's a probosal to add an alignmentof operator to the standard but in the meanwhile you can rely on simply wrapping it up in an union togheter with the most restrictive type you can think of on your platform (probably an int will suffice) that should work good enough on most present platforms and implemntations.

Share this post


Link to post
Share on other sites
You should be able to use a union and templates to generate a suitable alignment, although it may give worse alignment than is actually required. This technique was published in Andrei Alexandrescu's Discriminated Unions articles in his Generic<Programming> column, available online (google it). The code is (my implementation, with different names):
template < bool CONDITION, typename TRUE_RESULT, typename FALSE_RESULT >
struct Select;

template < typename TRUE_RESULT, typename FALSE_RESULT >
struct Select< true, TRUE_RESULT, FALSE_RESULT >
{
public:
typedef TRUE_RESULT Result;
};

template < typename TRUE_RESULT, typename FALSE_RESULT >
struct Select< false, TRUE_RESULT, FALSE_RESULT >
{
public:
typedef FALSE_RESULT Result;
};

struct TypeListEnd
{
};

template < typename HEAD, typename TAIL >
struct TypeList
{
};

struct Unknown;

template < typename TYPE >
struct Structify
{
TYPE type;
};

typedef TypeList< char,
TypeList< short int,
TypeList< int,
TypeList< long int,
TypeList< float,
TypeList< double,
TypeList< long double,
TypeList< char*,
TypeList< short int*,
TypeList< int*,
TypeList< long int*,
TypeList< float*,
TypeList< double*,
TypeList< long double*,
TypeList< void*,
TypeList< Unknown (*)(Unknown),
TypeList< Unknown* Unknown::*,
TypeList< Unknown (Unknown::*)(Unknown),
TypeList< Structify< char >,
TypeList< Structify< short int >,
TypeList< Structify< int >,
TypeList< Structify< long int >,
TypeList< Structify< float >,
TypeList< Structify< double >,
TypeList< Structify< long double >,
TypeList< Structify< char* >,
TypeList< Structify< short int* >,
TypeList< Structify< int* >,
TypeList< Structify< long int* >,
TypeList< Structify< float* >,
TypeList< Structify< double* >,
TypeList< Structify< long double* >,
TypeList< Structify< void* >,
TypeList< Structify< Unknown (*)(Unknown) >,
TypeList< Structify< Unknown* Unknown::* >,
TypeList< Structify< Unknown (Unknown::*)(Unknown) >, TypeListEnd > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > AllAlignableTypes;

template < typename TYPE_LIST, std::size_t targetSize >
struct RemoveTypesWithWorseAlignmentRestrictions;

template < std::size_t targetSize >
struct RemoveTypesWithWorseAlignmentRestrictions< TypeListEnd, targetSize >
{
public:
typedef TypeListEnd Result;
};

template < typename Head, typename Tail, std::size_t targetSize >
struct RemoveTypesWithWorseAlignmentRestrictions< TypeList< Head, Tail >, targetSize >
{
public:
typedef typename RemoveTypesWithWorseAlignmentRestrictions< Tail, targetSize >::Result MinimalTail;
typedef typename Select< sizeof(Head) <= targetSize, TypeList< Head, MinimalTail >, MinimalTail >::Result Result;
};

template < typename TYPE_LIST >
union ConfigurableUnion;

template < typename HEAD >
union ConfigurableUnion< TypeList< HEAD, TypeListEnd > >
{
HEAD head;
};

template < typename HEAD, typename TAIL >
union ConfigurableUnion< TypeList< HEAD, TAIL > >
{
HEAD head;
ConfigurableUnion< TAIL > tail;
};

template < typename TYPE >
struct WorstAlign
{
private:
typedef typename RemoveTypesWithWorseAlignmentRestrictions< AllAlignableTypes, sizeof(TYPE) >::Result MinimumAlignmentTypes;
public:
typedef ConfigurableUnion< MinimumAlignmentTypes > WorstAlignmentType;
};

And is used as such:
#include <new>
#include "Align.h"

typedef unsigned char byte;

class DesiredType
{
};

class MyClass
{

private:

union
{
WorstAlign< DesiredType >::WorstAlignmentType align;
byte mem[sizeof(DesiredType)];
} object;

public:

MyClass()
{
new (&object.mem[0]) DesiredType();
}
~MyClass()
{
reinterpret_cast< DesiredType & >(object.mem[0]).~DesiredType();
}

};

I doubt this will really gain you much if anything though. Are you sure that an aligned byte array is the best solution to your problem?

Enigma

Share this post


Link to post
Share on other sites
Thanks for the replies.

Quote:
Original post by defferWhy do you want to hide the variable as a byte array? Not to call it's default constructor, maybe? If it's so important, why don't you try making a non-default constructor, of the potential member, that does nothing, then call it by default in your class, that has the member.


I was trying to find a generic approach that didn't depend on altering the class of the variable.

Here's what I'm thinking of:

template<class T>
class optional
{
public:
optional();
explicit optional(const T&);

bool valid(){return valid_;}

void set(const T&);
T& get();
const T& get()const;
private:
bool valid_;
byte variable_[sizeof(T)],
};




Quote:

you can rely on simply wrapping it up in an union togheter with the most restrictive type you can think of on your platform (probably an int will suffice) that should work good enough on most present platforms and implemntations.


If the aligment is wrong, I think my code will still compile. Do you know of a way to check that the allignment is correct?

Quote:

I doubt this will really gain you much if anything though. Are you sure that an aligned byte array is the best solution to your problem?


I was trying to make it so that I could declare a variable of a certain type on the stack and have no dynamic allocation.

I considered using a memory pool to avoid dynamic allocation, but this creates issues as to which classes have access to the pool and what is responsible for creating and destroying the pool.

If there are other options available that you know of, I'd happily consider them.

As far as the rest of your post goes, It might be a while before I can tell exactly how that works, but doesn't it just find the smallest type with the required alignment and couldn't that be simplified by using the largest class available (albeit by increasing the overhead in most cases).

Also, which compiler do you use? I'd heard that the solution you suggested theoretically works, but many compilers can't cope with the template complexity.

Share this post


Link to post
Share on other sites
Quote:
original post by Nitage:
If there are other options available that you know of, I'd happily consider them.

Difficult to say without knowing more about the specific problem. What does it mean for an optional member to be present/absent? Would a default null value suffice? Does dynamic allocation really have too much overhead? etc.

As to the code I posted, yes, you could just use the most restrictive type at the expense of some possibly wasted space, but you'd still probably need to do some template magic for true safety since the most restrictive type may vary from platform to platform. The code will compile on gcc 3.3.1 (still waiting for a minGW port of 4.x) and VC++ 7.1, although the Borland compiler barfs on it.

Enigma

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this