-
解引用空指针,例如解引用空的this指针、解引用空的函数指针
下面的代码尽管能正常运行,但c->fun()等价于(*c).fun(),也就是对空指针解引用了
#include <iostream> struct C {void fun(){std::cout<<"fun"<<std::endl;} };int main(int argc, char *argv[]) {C* c = nullptr;c->fun();//funreturn 0; }
-
解引用end迭代器
因为end是指向容器后面的真空区域
std::vector<int> v = {1,2}; int* begin = &*v.begin();//正确 int* end = &*v.end();//错误,未定义行为 int* end = v.data()+v.size();//正确写法
-
有符号整型溢出是未定义行为,而无符号整型允许溢出
#include <iostream> #include <climits>int main(int argc, char *argv[]) {int a = INT_MAX;int b = a+1;//有符号整型溢出并不能保证回环(x86中才会回环),它是未定义行为std::cout<<b<<std::endl;//-2147483648unsigned int c = UINT_MAX;unsigned int d = c+3;//无符号整型允许溢出,会回环std::cout<<d<<std::endl;//2return 0; }
-
左移溢出(left shift)
int i = 1<<32; unsigned int j =1<<32;
-
未写返回值是未定义行为,程序直接崩溃,但不显示错误
cmake中这样写将未写返回值的警告转为错误
target_compile_options(main PRIVATE -Werror=return-type) -
读取未初始化的变量、已析构的对象
从语法上来说,移动过的对象是可以访问的,但不要这样做
下面代码在gcc中s为空,但在msvc中不清空。string字符串小于15字节时,小字符串优化将其存放在union结构体的local_buff中,因此移动和拷贝操作等价std::string s = "hello"; std::string s2 = std::move(s); std::cout<<s<<std::endl;
-
memcpy函数的dst和src都不能为空指针、不能重叠
因为其中使用了__restrict关键字,告诉编译器该指针与其它指针是相互独立的,不会重叠,便于编译器进行优化
void fun(int* p1, int* p2){*p1 = 2;*p2 = 3;//可能p2指向与p1相同std::cout<<*p1+*p2<<std::endl;//5或6 } void fun2(int* __restrict p1, int* __restrict p2){*p1 = 2;*p2 = 3;std::cout<<*p1+*p2<<std::endl;//等价于直接返回5 }
如果确实需要进行就地移动,那就使用memmove(dst, src, size_t)
-
T类型的指针必须对齐到alignof(T),构造未对齐的指针属于未定义行为
malloc产生的指针只保证对齐到max_align_t,而new能保证对齐到alignof(T)
#include <iostream> struct alignas(64) A//alignas是一个对齐说明符,用于指定变量或类型的最小对齐要求 {int i;char j; }; int main(int argc, char *argv[]) {A* a1 = (A*)malloc(sizeof(A));//错误A* a2 = new A;//正确return 0; }
//错误,buf只是大小为4,没有对齐到4字节,不能直接作为int*使用 char buf[sizeof(int)]; int* p = (int*)buf; //正确 alignas(alignof(int)) char buf[sizeof(int)]; int* p = (int*)buf;
-
多个线程访问同一个对象,其中有一个是写操作,是未定义行为
-
死锁也是未定义行为。
多个线程对多个锁的上锁顺序不同就会死锁。可以使用std::lock(m1, m2)、std::unlock(m1,m2)来上锁和解锁 来避免
重复加锁导致死锁是未定义行为:改用recursive_mutex或使用适当的条件变量std::mutex m; m.lock(); bool res = m.try_lock();//重复加锁是未定义行为,即使是try_lock上锁 std::cout<<res<<std::endl;//不一定 m.unlock();