C++未定义行为(undefined behavior)
衡量一个人是否真正活着的根本方法,就是看他是否有意愿、有能力做出主动的选择。 在计算机程序设计中,未定义行为(undefined behavior)是指行为不可预测的计算机代码。这是一些编程语言的一个特点,最有名的是在C语言中。在这些语言中,为了简化标准,并给予实现一定的灵活性,标准特别地规定某些操作的结果是未定义的,这意味着程序员不能预测会发生什么事。 一个问题 此问题摘自知乎: 对顺序容器 ( vector ) 的访问: 如果使用 operator[] 访问容器,下标越界是未定义行为。 同样摘取一些回答 回答一: C++ 的设计理念之一,就是你不需要为你不使用的特性付出代价。如果你能确保你的下标不越界,C++就不会进行检查。 回答二: 检查就表示有运算判断的开销,C++将效率放在第一位,假设用户之前已经对[]访问的下标做过检查了,在一个大量访问的for循环中,但是vector还是自作聪明的每次都判断一次下标越界,这个效率影响你可想而知!你会不会在这个情况下骂它管的太多呢。所以说将所有的权利都交给你,vector不做太多自作聪明的处理。 什么是未定义 未定义行为(Undefined Behavior)是指语言标准未做规定的行为。同时,标准也从没要求编译器判断未定义行为,所以这些行为有编译器自行处理,在不同的编译器可能会产生不同的结果,又或者如果程序调用未定义的行为,可能会成功编译,甚至一开始运行时没有错误,只会在另一个系统上,甚至是在另一个日期运行失败。当一个未定义行为的实例发生时,正如语言标准所说,“什么事情都可能发生”,也许什么都没有发生。 下文会罗列C++中的一系列未定义结果和未定义行为,持续整理更新。 未定义的结果 1、当我们赋给带符号类型一个超出它表示范围的值时,结果是未定义的。
2、函数体之内定义的变量:未初始化(uninitialized),其值undefined。 3、算术表达式有可能产生未定义的结果 数学性质本身:除数为0 未定义的行为 未定义行为,无法预估Runtime会发生什么(unpredictable:normal、crashing、incorrect results)。 1、解引用空指针、非法迭代器或者尾后迭代器都是未定义行为 2、访问一个无效数组索引,下标越界 3、当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果是未定义的。 实际执行时通常发生的是对象的derived成员没有被销毁。 5、释放一个非new分配的内存,或者将相同的指针值释放多次,其行为是未定义的。 6、string s(s2,pos2); // s是string s2从下标pos2开始的字符拷贝,如果pos2>s2.size(),构造函数的行为未定义 7、试图比较两个无关地址是未定义行为 8、对于那些没有指定执行顺序的运算符来说,如果表达式指向并修改了同一个对象,将会引发错误并产生未定义的行为。 int i=0; cout<<i<<" "<<++i<<endl; // 未定义 // 编译器可能先求++i的值,再求i的值;也可能先求i的值,再求++i的值。注意与print函数的区别。 *beg=toupper(*beg++); // 未定义 9、对有符号数进行左移操作可能会改变符号位的值,因此是一种未定义的行为。移位运算符右侧的运算对象一定不能为负,而且值必须严格小于结果的位数,否则就会产生未定义的行为。 10、使用static_cast将void*转换成其他类型指针,必须确保转换后所得的类型就是指针所指的类型。类型一旦不符,将产生未定义行为。 double d; void* p=&d; double *dp=static_cast<double*>(p); 11、const_cast只能改变运算对象的底层const,如果对象本身是一个常量,使用const_cast执行写操作就会产生未定义行为。 12、不要使用get初始化另一个智能指针或为智能指针赋值,否则将会产生两个独立的shared_ptr指向相同的内存,这将产生未定义行为。 13、delete []p;如果忘记[],其行为是未定义的。 删除单一对象的指针加[],其行为也是未定义的。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |