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

C++ 条件运算符中的未定义行为,c++,iterator,valgrind,undefined-behavior,conditional-operator,C++,Iterator,Valgrind,Undefined Behavior,Conditional Operator,我必须分享这一点: 我因以下涉及条件运算符的小错误被挂断了整整两天 这很容易纠正,但我想知道: 为什么要编译错误代码 虫子在干什么 为什么这么难找到 错误代码: std::map<int, some_class> my_map; int key_ctr = 0; //... std::map<int, some_class>::iterator it_next = ke

我必须分享这一点:

我因以下涉及条件运算符的小错误被挂断了整整两天

这很容易纠正,但我想知道:

  • 为什么要编译错误代码
  • 虫子在干什么
  • 为什么这么难找到
  • 错误代码:

     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!!!!
    
      // .....
    
    这是完全没有帮助的,并指出我在错误的董事(我认为我是分配太多的堆,不知何故)

    再说一遍

  • 为什么要编译错误代码
  • 虫子在干什么
  • 为什么这么难找到
  • 谢谢孩子们。

    1)编译器只检查语法和格式良好的程序。由您来确定逻辑错误

    2) 这是未定义的行为。原因如下:


    实际上,您可以将范围缩小到:

    It it_next = it_next = whatever;
    
    不管是什么都不重要。重要的是,在执行完整语句之前(
    ),它的下一步是未初始化的。这就是问题所在

    It it_next = ...
    
    第二部分试图做到但是首先,它尝试评估右侧的内容。哪个是
    it\u next=Which
    。它调用
    it\u next.operator=(无论什么)
    。因此,您正在对未初始化的对象调用成员函数。这是未定义的行为。Ta大哥

    3) 所有未定义的行为都很难追踪。这就是为什么你至少应该意识到常见的情况

    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
    

    这个标题有点误导人。问题不在于三元运算符,而在于使用未初始化的变量。严重缺少括号。不是开玩笑。@DavidRodríguez dribeas哪个是未初始化的变量?@john刚刚编辑了我的答案来解释。我喜欢这部分——“为什么要编译错误代码?”。如果你想出了一个编译器,而它没有编译错误代码,你将是一个亿万富翁。什么是未定义的行为
    it_next
    由三元运算符中的两个表达式赋值,然后执行自赋值。“我看不到UB。”卢钦格里戈谢谢你的解释。这真的很棘手。我并不奇怪OP感到有点委屈。我没有注意到非POD位。gcc也抱怨
    inta=a=10。但在本例中,情况更糟,因为迭代器是一个UDT,而不是一个原始指针(我一直认为它是)ᵩ, 我的程序相当大,涉及大量的库。因此,
    -Werror
    将导致来自外部库(我无法控制)的警告导致编译崩溃。但我无法修复这些问题,因为它们位于外部库中。@Matthew Clang有一个很棒的
    -Wno system headers
    命令行参数,使其不会从指定为
    -issystem/path/to/library
    的任何目录中的文件生成警告。我希望其他编译器也有类似的功能。
    It it_next = it_next = whatever;
    
    It it_next = ...
    
    $ 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