Boost logo

Boost :

From: Fernando Cacciola (fernando_cacciola_at_[hidden])
Date: 2005-10-28 14:52:14


Michael Shepanski wrote:
> The code below fails a compile-time assertion in boost 1.32.0 on MSVC
> 7.1.
>
> class D
> {
> virtual ~D();
> };
>
> class E : virtual public D
> {
> virtual ~E();
> unsigned long long m_i;
> };
>
FYI:

The following article by Tom Lokovic explains a technique for calculating
the alignment of a data type. His technique is exactly the same used by
boost::alignment_of<>, so we can consider the article an explanation of how
alignment_of<> works.

http://www.monkeyspeak.com/alignment/

Basically:

********** Explanation of alignment_of<> **********************

Appendix 1 of the article contains a proof of the following interesting
claim:

"For every type T, sizeof(T) is an integer multiple of T's stride S"

(Tom calls "stride of T" to the "alignment requirements of T")

Read the proof if you're not convinced. It basically says that C/C++
compilers chooses sizeof(T) as a multiple of the alignment of T because that
allows you to arrange instances of T one right after another in an array
without violating T's alignment requirements.

And Appendix 2 contains a proof of:

"For every struct type T, sizeof(T) is an integer multiple of the stride of
each of T's members"

It basically says that when the compiler creates an object containing both T
and U, it must give it a size such that, if 2 instances of the T+U are
placed one after another in an array, each member T or U must be itself
properly aligned, and for that, the total size must be a multiple of each
member's alignment.

So,

Say we have a type 'T' and we form a new type, Tchar, adding a 'char' to it.
Now say we put 2 instances of Tchar into an array. However the char is added
into Tchar, the T member of the second Tchar must be properly aligned w.r.t
to T's requirement, so the compiler needs to arrange Tchar as to guarantee
that.
Furhtermore, since a char can be placed anywhere in memory, that is, it's
alignment is 1, we know that the compiler has really just 2 choices: either
it reuses the padding within T to store the 'char', in which case
sizeof(T)==sizeof(Tchar), or it extends the storage needed by an amount
equivalent to the alignment of T, or a multiple of that (it has to be like
that to make sure each T member is properly placed in an array of Tchar)

That is, sizeof(Tchar)-sizeof(T) must be a multiple of the alignment of T.

boost::alignment_of<> returns either sizeof(T) or sizeof(Tchar)-sizeof(T),
and both are required to be multiples of the alignment of T.

It uses the following template to generate Tchar

template <typename T>
struct alignment_of_hack
{
  char c;
  T t;
  alignment_of_hack();
};

********** End of Explanation of alignment_of<> **********************

Now, I checked some facts with your E class in VC7.1 and the results are
interesting:

The sizeof(E) is 20

And according to the explanation of how to calculate the alignment of E, a
struct adding a 'char' to E should have a size larger than 20 in an amount
multiple of the alignment of T.

struct Echar
{
  E e ;
  char c;
} ;

struct charE
{
  char c;
  E e ;
} ;

sizeof(Echar) -> 24
sizeof(charE) -> 32

As you can see, the true alignment of T is 4, while 12 is just 3 times that.

As you know by now, the real problem here is that type_with_alignment<>
cannot really take as argument "any" multiple of the alignment becasue it
cannot match any multiple with its type list.

As Martin Bonner suggested, one solution is to factorize the result of
alignment_of<> so it returns not just any multiple. Unfortunately, we can't
say that the alignment _ought_ to be a power of 2 can we?

An alternative solution that, at least, would work with this very specific
example, is to compute it as the minimun of sizeof(charT)-sizeof(T) and
sizeof(Tchar)-sizeof(T)
That is, adding the char both before and after, and taking the least
difference.

HTH

-- 
Fernando Cacciola
SciSoft
http://fcacciola.50webs.com/ 

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk