8

多数の関数ポインターを保持するクラスがあり、オブジェクトが構築されるときにそれらすべてを NULL に初期化したいと考えています。これを行うために、最初のポインターから最後のポインターまでのメモリ位置で memset を使用することを計画していましたが、これが 100% の時間で機能するかどうかはわかりません。

これらの関数ポインタがクラス内で連続して宣言されている場合、それらのメモリ位置も連続していることが保証されていますか? パディングバイトもNULLに設定されるだけなので、パディングは私がやろうとしていることには影響しないと思います。

クラスの実装例

class C
{
private:
    void (*func1)();
    void (*func2)();
    void (*func3)();
    void (*func4)();
};
4

4 に答える 4

10

宣言された順序でアドレスが増加するように表示されることが保証されています。これは一般に、アクセス指定子を介在させないデータ メンバーに当てはまります。したがって、クラスに他のデータ メンバーが存在する場合、それらが介入できる唯一の方法は、そこにアクセス指定子がある場合です。

パディング バイトを変更しても安全であるとは限りません。実装がデータメンバーの間に「何か重要なもの」を入れないことが保証されているとは思いませんが、実装がそこに入れたいと思うものはすぐには思いつきません。奇妙に設計された正確なマーキング GC の型情報は? バッファ オーバーランをテストするための認識可能な値は?

all-bits-zero が null 関数ポインターを表すことは保証されていません。

次のようなものを使用して、すべてのビットがゼロの表現の問題に対処できます。

std::fill(&func1, &func4 + 1, (void(*)(void))0);

しかし、それでもパディングの問題は残ります。配列にはパディングがないことが保証されていますが、(標準では) クラスにはパディングされていません。実装で使用される ABI は、上記のクラスが 4 つの関数ポインターの配列と同じようにレイアウトされるようにするために必要な程度まで構造体レイアウトを指定する場合があります。

別の方法として、次のことを行います。

struct function_pointers {
    void (*func1)();
    void (*func2)();
    void (*func3)();
    void (*func4)();
};

class C : private function_pointers
{
public:
    C() : function_pointers() {}
};

イニシャライザは、それ自体のインスタンスがデフォルトで初期化されている場合でもfunction_pointers()、(ユーザーが宣言したコンストラクタがないため) のメンバーfunction_pointersがゼロで初期化されることを指示します。アクセスするためにもう少し入力したい場合などは、基本クラスではなくデータメンバーにすることができます。Cfunction_pointersfunc1

CC++03 では、現在非 POD であることに注意してください。C++11 ではC、この変更後も標準レイアウトのままですがC、 で定義されたデータ メンバーが存在する場合は標準レイアウトではなく、自明なクラスではありません。したがって、POD/標準/自明性に依存している場合は、これを行わないでください。代わりに の定義をCそのままにして、集約初期化 ( C c = {0};) を使用して C のインスタンスをゼロで初期化します。

于 2013-03-15T11:13:46.877 に答える
3

最初にこれを行います。

class C
{
public:
    C() : func1(nullptr), func2(nullptr), func3(nullptr), func4(nullptr)
    { };
private:
    void (*func1)();
    void (*func2)();
    void (*func3)();
    void (*func4)();
};
于 2013-03-15T11:13:04.103 に答える
1

自明でないオブジェクト、特にポリモーフィックなオブジェクト (仮想関数を持つ、または仮想メソッドを持つ基本クラスから派生するものなど) では決して memset を使用しないでください。それを行うと、 vtableを指すvptrが爆破されます。大惨事!

vptrvtableは、ポリモーフィックな動作を実装するために使用されるため、これらの非表示のクラス メンバーを尊重します。

memset は、オブジェクトについて話すときではなく、ビットとバイトについて話すときに使用する必要があります。

自明でないオブジェクトを尊重し、memsetにノーと言ってください:)

于 2013-03-15T11:32:26.717 に答える
1

自分が何をしているのか本当によくわかっていない限り、これを C++ で絶対に行わないでください。これは非常にエラーが発生しやすく、コードの将来の保守担当者 (それはあなたかもしれません!) は、存在するすべての落とし穴を認識しない可能性があり、物事がひどくうまくいかない可能性があります。これを実現する C++ の方法は、nullptr(C++11 を使用している場合) または0.

于 2013-03-15T11:12:28.950 に答える