条件运算符中的未定义行为

时间:2012-10-25 20:50:29

标签: c++ iterator valgrind undefined-behavior conditional-operator

我必须分享这个:

我在涉及条件运算符的以下琐碎错误中被挂了2天。

这是一个很容易的纠正,但我想知道:

  1. 为什么有错误的代码会编译?
  2. 虫子在做什么?
  3. 为什么这么难以追查?
  4. 越野车代码:

     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 个答案:

答案 0 :(得分: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)所有未定义的行为都难以追踪。这就是为什么你至少应该意识到常见的情况。

答案 1 :(得分: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