2010-10-08

standard-layout classのささいな条件

あるクラスがstandard-layout classの条件を満たしたときに保証される動作はいくつかあるが、その中でもとくに重要なものに、クラスのオブジェクトへのアドレスは、クラスの最初の非staticデータメンバーのサブオブジェクトへのアドレスに等しい。というものがある。

struct A
{
    int x ; int y ;
} ;

A a ;

A * a_ptr = &a ;
int * ptr = reinterpret_cast<int *>( a_ptr ) ;

この場合、ptrはa.xを指す。これは規格で保証されている。ちなみにこの時、++ptrがa.yを指す保証はない。なぜならば、実装はデータメンバーの間にpaddingを入れるかもしれないからだ。ともかく、このクラスのオブジェクトへのアドレスが、クラスの最初の非staticデータメンバーへのサブオブジェクトのアドレスに等しいというのは、重要な保証だ。

ところで、standard-layout classとなるためには、かなり厳しい条件を満たさなければならないわけだが、その中に、「最初の非staticデータメンバーと、基本クラスとで、同じ型を使わない」というものがある。

// standard-layout classではない例
struct A { } ;
struct B : A // 基本クラス
{
    A a ; // 最初の非staticデータメンバー
    int data ; // 二つ目の非staticデータメンバー
} ;

なぜかというと、基本クラスのサブオブジェクトと、データメンバーaは、別々のアドレスを割り当てられていなければ、困るからだ。

struct A { } ;
struct B : A { A a ; } ;

B obj ;

A * p1 = &obj ; // 基本クラスのサブオブジェクトへのアドレス
A * p2 = &obj.a ; // データメンバーへのアドレス

// p1 != p2が保証される

なぜならば、クラスBに、クラスAというサブオブジェクトは、二つあるからだ。p1 != p2を保証するためには、このようなクラスには、standard-layout classになってもらっては困る。

No comments: