Reputation: 4114
I had to share this:
I got hung up for 2 full days on the following trivial error involving the Conditional Operator.
It's an easy correction, but I would like to know:
buggy code:
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!!!!
// .....
Clearly, I wrote the Conditional Operator incorrectly. Eveyrthing works totally fine when I finally found and corrected this bug:
correct code:
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!
My program was just hanging when it got near the buggy part - as if it were in an infinite loop. When I ran it with valgrind, I got stuff like
....
==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.
Which was totally unhelpful and pointed me in the wrong director (I thought I was allocating too much on the heap, somehow).
Again,
Thanks kids.
Upvotes: 4
Views: 528
Reputation: 168866
3 Why it was so damn hard to track down?
Because you didn't have compiler warnings turned on?
$ 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
Upvotes: 7
Reputation: 258648
1) The compiler only checks for syntax and a well-formed program. It's up to you to spot the logical bugs.
2) It's undefined behavior. And here's why:
whatever_non_POD_type it_next = condition ? it_next = whatever1 :
it_next = whatever2;
Actually, you can narrow it down to:
It it_next = it_next = whatever;
it doesn't really matter what whatever is. What matters is that until the full statement executes (;
is reached), it_next
is uninitialized. That's what the
It it_next = ...
part attempts to do. But first, it attempts to evaluate what's on the right hand side. Which is it_next = whatever
. Which calls it_next.operator = (whatever)
. So you're calling a member function on an un-initialized object. Which is undefined behavior. Ta-da!!!
3) All undefined behavior is hard to track down. That's why you should at least be aware of common situations.
Upvotes: 7