неопределенное поведение в условном операторе

Я должен был поделиться этим:

Я завис на 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

Решение

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) Все неопределенное поведение трудно отследить. Вот почему вы должны хотя бы знать о распространенных ситуациях.

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
7

По вопросам рекламы [email protected]