1

私は関数を持っていて、それを呼び出します:

Class1& Class2::get()
{
   return *m_ptr;
}

Class1& c = m_class2->get();

m_ptr はカスタム スマート ポインターであり、m_ptr.m_p が 0 であることをデバッガーで確認できます。また、実際に 0 を返す演算子 T* 内で確認できます。ただし、c (&c) のアドレスは NULL ではなく、0x30 です! 分解で私が見たもの:

13059       return *m_ptr;
eaabbc7e:   mov 0x8(%ebp),%eax
eaabbc81:   add $0xb4,%eax
eaabbc86:   mov %eax,(%esp)
eaabbc89:   call 0xea9ce4c0  <operator T*>
eaabbc8e:   add $0x30,%eax
13060     }

line add $0x30,%eax の直前に、%eax が 0 であることがわかります。これは、オペレーターが正しく NULL を返したことを示しています。

0x30を追加する行がここにあるのはなぜですか???

4

1 に答える 1

4

答えるのに十分な情報はありませんが、あなたのコメントは多重継承を含むことを示唆しており、テンプレートパラメータがそれ自体ではなく派生クラスでClass2あると推測するのは危険です。TClass2

したがってoperator T*、この派生クラスへのポインタを返します。を逆参照して与えるClass2&には、に変換する必要がありますClass2*。これには、コンパイラがオブジェクト内の基本クラスのサブオブジェクトをどのようにレイアウトするかに応じて、ポインタにオフセットを追加する必要があります。

明らかに、これはポインタがnullでない場合にのみ有効です。これが、参照の初期化に結果のみを使用している場合でも、nullポインターを逆参照してはならない理由の1つです。

関数がを返した場合、Class2*期待どおりにnullポインタを取得します。nullをnullに変換するには、その変換が必要です。あなたの場合、ポインタを逆参照することによって未定義の動作を呼び出しているので、変換を実行する前にコンパイラがnullをチェックする必要はありません。

于 2012-04-19T10:16:33.480 に答える