4

私はこれを共有しなければなりませんでした:

条件演算子に関連する次の些細なエラーで、丸2日間ハングアップしました。

簡単な修正ですが、知りたいのは次のとおりです。

  1. バグのあるコードがコンパイルされたのはなぜですか?
  2. バグは何をしていましたか?
  3. 追跡するのがとても大変だったのはなぜですか?

バギーコード:

 std::map<int, some_class>   my_map;
int key_ctr = 0;
 //...
std::map<int, some_class>::iterator it_next   =  
                                            key_ctr == 0  ?
                                 it_next  =  my_map.begin()      // BUG!!!
                                 :
                                 it_next  =  --my_map.end();     // BUG!!!!

  // .....

明らかに、私は条件演算子を間違って書きました。私がこのバグを見つけて修正したとき、Eveyrthingは完全に正常に機能します。

正しいコード:

 std::map<int, some_class>   my_map;
int key_ctr = 0;
 //...
std::map<int, some_class>::iterator it_next   =  
                                            key_ctr == 0  ?
                                 my_map.begin()              // CORRECTED!
                                 :
                                 --my_map.end();             // CORRECTED!

私のプログラムは、バグのある部分に近づくと、まるで無限ループにあるかのようにぶら下がっていました。valgrindで実行すると、次のようなものが得られました

....
==24570== Warning: set address range perms: large range [0x1a7731000, 0x1c5f79000) (defined)
==24570== Warning: set address range perms: large range [0x1c5f79000, 0x1e47c1000) (defined)
==24570== Warning: set address range perms: large range [0x1e47c1000, 0x203009000) (defined)
==24570== Warning: set address range perms: large range [0x203009000, 0x221851000) (defined)
.....
==3733== More than 10000000 total errors detected.  I'm not reporting any more.

これはまったく役に立たず、間違ったディレクターを指さしました(どういうわけか、ヒープに割り当てすぎていると思いました)。

また、

  1. バグのあるコードがコンパイルされたのはなぜですか?
  2. バグは何をしていましたか?
  3. 追跡するのがとても大変だったのはなぜですか?

子供たちに感謝します。

4

2 に答える 2

7

1)コンパイラは、構文と整形式のプログラムのみをチェックします。論理的なバグを見つけるのはあなた次第です。

2)それは未定義の振る舞いです。そして、その理由は次のとおりです。


whatever_non_POD_type it_next = condition ? it_next = whatever1 : 
                                            it_next  = whatever2; 

実際には、次のように絞り込むことができます。

It it_next = it_next = whatever;

何が何であるかは実際には問題ではありません。重要なのは、完全なステートメントが実行される(;到達する)まで、it_next 初期化されていないということです。それが

It it_next = ...

一部はやろうとします。しかし、最初に、右側にあるものを評価しようとします。これはit_next = whateverです。呼び出しますit_next.operator = (whatever)。したがって、初期化されていないオブジェクトでメンバー関数を呼び出しています。これは未定義の動作です。タダ!!!

3)未定義の動作はすべて追跡が困難です。そのため、少なくとも一般的な状況に注意する必要があります。

于 2012-10-25T20:53:11.787 に答える
7

3なぜ追跡するのがとても大変だったのですか?

コンパイラの警告がオンになっていないので?

$ g++ -std=c++0x -pedantic -Wall -Werror -g    m.cc   -o m
cc1plus: warnings being treated as errors
m.cc:10: error: operation on ‘it_next’ may be undefined
m.cc: In function ‘void __static_initialization_and_destruction_0(int, int)’:
m.cc:6: error: operation on ‘it_next’ may be undefined
make: *** [m] Error 1
于 2012-10-25T20:59:02.987 に答える