11

それで、大規模なサーバー アプリケーションの数時間に及ぶ過酷なデバッグ セッションをやり遂げました。エラーは最終的に、コンストラクターのほとんど目立たないタイプミスにまで至りました。基本的には、次のようなものでした。

template <class T>
class request_handler
{
    public:

    request_handler(T& request, Log& error_log) 
      : m_request(m_request), m_error_log(error_log)
     { 
       /*... some code ... */
     }

    ...
};

バグが見えますか?まあ、私はしませんでした。問題は、イニシャライザ リストの小さなタイプミスですm_request(m_request)。初期化されていない参照を自分自身に割り当てています。明らかに、それは読むことになっていますm_request(request)

これで、メンバー変数m_requestの型はT&. それで、ここで初期化されていない変数を使用していることをコンパイラが警告しなかった理由はありますか?

-Wall私が言うなら、フラグでGCC 4.6を使用します:

int x;
x = x;

...警告が表示されます:warning: ‘x’ is used uninitialized in this function [-Wuninitialized]

m_requestでは、それ自体に代入したときにコンパイラが警告を出さなかったのはなぜでしょうか。それは私を何時間も煩わしくさせなかったでしょう。

4

2 に答える 2

11

追跡する迷惑なバグ。結局のところ、これで暗黙のうちに失敗するテンプレートは必要ありません。これでうまくいきます:

class C {
        int a, b;
public:
        C(int t, int z) : a(a), b(z) { };
};

Clang はこれについて警告し-Wuninitializedます。

gcc関係者に朗報です。gnuの bugzilla によると、gcc 4.7.0 ではこれが修正されています。

アップデート

gcc 4.7.0 では、次の-Wself-init警告を取得するために追加します ( sbellefで検証済み)。

tst.cc: コンストラクター 'C::C(int, int)': tst.cc:4:9: 警告: 'C::a' はそれ自体で初期化されています [-Wuninitialized]

于 2012-05-21T01:34:12.660 に答える
3

メンバーにコンストラクターのパラメーターと同じ名前を使用するというトリックを使用するのが好きです。

template <class T>
request_handler(T& request, Log& error_log) 
 : request(request), error_log(error_log)
{ 
  /*... some code ... */
}

これにより、常にエラーが防止されます。requestただし、関数本体はメンバーではなく引数を参照するため、注意が必要です。もちろん、これは参照などの単純な型には関係ありませんが、クラスにはお勧めしません。

于 2012-05-21T01:42:28.303 に答える