可変サイズのクラス-C ++
-
06-07-2019 - |
質問
このように定義されたクラスであるクラスを見ました。
class StringChild : public StringBase
{
public:
//some non-virtual functions
static StringChild* CreateMe(int size);
private:
unsigned char iBuf[1];
};
静的ファクトリー関数には、次の実装があります。
return new(malloc(__builtin_offsetof(StringChild ,iBuf[size]))) StringChild();
私が理解する限り、この関数はこのクラスを拡張するために新しい配置を使用しています。
これは、メンバーが1つしかなく、ヒープに割り当てられているためにのみ安全ですか?
解決
これは、プレーンCの可変長配列の非可用性を回避するために使用された古いCのトリックです。はい。目的のサイズと配置をそこにオブジェクトを更新します)。割り当てられたメモリの終わりをさまようしない限り安全ですが、少なくともいくつかのメモリデバッガを混乱させる傾向があります。
この手法を使用する際に絶対に確認しなければならないことの1つは、可変長配列がオブジェクトレイアウトの最後の要素であることです。それ以外の場合は、他の内部変数を調べます。
しかし、私はファクトリー関数の実装について少し疑っています-'size'パラメーターが実際に望ましい配列サイズであると思いますか?また、「delete」ではなく「free」を使用して上記のメモリを解放する必要があることを忘れないでください。後者はほとんどの場合に機能する可能性があります。
メモリをこの方法で管理する必要がある理由について説得力のある理由がない限り、単純に配列をstd :: vectorに置き換えます。
他のヒント
これは、iBufが構造の最後のメンバーである場合、PODには問題ありません。非PODの問題は、たとえばコンパイラは自由にpublic / private / protectedメンバーを並べ替えることができ、仮想ベースクラスは最も派生したオブジェクトIIUCの終わりになります。
あなたの構造は非POD(基本クラスを持っている)なので、お勧めしません。
また、このようなインスタンスを作成する場合
return new(malloc(__builtin_offsetof(StringChild ,iBuf[size]))) StringChild();
mallocによって取得されたメモリはfreeで解放する必要があるため、次のようにインスタンスを削除する必要があります。
obj->~StringChild();
free(obj);
割り当てに :: operator new()
を使用したい場合があります
厳密に言えば、 StringChild
は StringBase
から派生しているため、安全ではありません。 C ++標準では、基本クラスのサブオブジェクトのレイアウトは指定されていません。条項10パラグラフ3:
基本クラスのサブオブジェクトが最も派生したオブジェクト(1.8)に割り当てられる順序は指定されていません。
StringChild
がPOD構造体である場合、このような手法は安全です。