2011-08-11 11 views
1

誰かがこのマクロを私に説明できるかどうか疑問に思っていました。C++マクロによるNULLポインタの発生

#define Q_DECLARE_PRIVATE(Class) \ 

inline Class##Private* d_func() { return reinterpret_cast<Class##Private 
*>(d_ptr); } \ 

inline const Class##Private* d_func() const { return reinterpret_cast<const 
Class##Private *>(d_ptr); } \ 

friend class Class##Private; 

QTを使用するアプリケーションがあり、次のスニペットの最後の行でアクセス違反例外が発生してクラッシュします。

class Q_GUI_EXPORT QWidget : public QObject, public QPaintDevice 
{ 
    Q_OBJECT 
    Q_DECLARE_PRIVATE(QWidget) 

full source here

と何が最後の行の中にNULLポインタの動作を引き起こすことができますか?

答えて

3

コンパイラは、すべての最高のそれを説明することができます。

g++ -E foo.cc 

は、プリプロセッサを通過した後、stdoutにfoo.ccを配置します。コンパイラが(特にトークンの貼り付けで)どのようなものが見えるかを見ることができます。

1

thisポインタはNULLですか?すべてのコードは、d_ptrクラスメンバーのアクセス関数を生成します。

+0

この行は、QListViewから継承するクラスをインスタンス化するときにヒットします。このクラスは、チェーンの途中で質問に表示される 'QWidget'を間接的に継承します。 –

+0

例外が発生したときに 'this'ポインタがNULLかどうかを確認できますか? –

1

マクロは、プライベートな実装クラスへのポインタを宣言することによってPimplイディオムを実装します。 ##ガベージプリプロセッサのカテナネーション演算子を使用してプライベートクラスの名前を作成しています。

d_ptrメンバーを取得するとNULLアクセスが発生する場合は、発信者がNULL->d_func()を実行している必要があります。それを探して呼び出し元をデバッグしてください。

#define DECLARE_HANDLE(name) struct name##__ {int unused;} typedef name##__* name; 

と使用方法:Windowsのヘッダから

1

YourHandleTypeがタイプ YourHandleType__

のポインタになり
struct YourHandleType__ 
{ 
    int unused; 
}; 
typedef YourHandleType__ * YourHandleType; 

DECLARE_HANDLE(YourHandeType); // Just any name, this isn't any type 

は、新しい構造体を作成します

tokenizer演算子##は、プリプロセッサで使用され、C/C++コンパイラによって利用されるフルネームを作成します。この場合、DECLARE_HANDLEは、呼び出し元に対して不透明で、異なるハンドル間で「変換なし」を提供するさまざまな型を作成できます。

関連する問題