总结了24个C++的大坑,你能躲过几个

总结了24个C++的大坑,你能躲过几个 前段时间给部门做了个C专题的分享主要分享了C语言里一些常见的坑在这里也分享给大家。以下是本文目录首先说下C和C语言有什么区别分享一个我在知乎上看见的回答C ≈ C with classes C with STLC面向机器编程C面向编译器编程C有个很重要的特性叫RAII个人认为可以多多使用相当方便关于RAII巧妙使用可以看我这两篇文章《RAII妙用之ScopeExit》《RAII妙用之计算函数耗时》。言归正传下面我一个一个的列出来C使用过程中常见的坑无符号整数的错误使用1for(unsignedinti 10; i 0; --i) { ... }上面这段代码会发生什么? 会死循环这里要注意下无符号整数的使用。容器的size()返回类型是无符号整数12345std::vectorint vec;vec.push_back(1);for(auto idx vec.size(); idx 0; idx--) {cout \n;}这段代码依旧会出现死循环原因参考上一条。memcpy、memset只适用于POD结构至于什么是POD类型其实解释起来挺麻烦的感兴趣的可以直接看cppreference的https://en.cppreference.com/w/cpp/named_req/PODTypeSTL遍历删除时注意迭代器失效问题123456789101112131415voiderase(std::vectorint vec,inta) {for(auto iter vec.begin(); iter ! vec.end();) {// 这个正确if(*iter a) {iter vec.erase(iter);}else{iter;}}for(auto iter vec.begin(); iter ! vec.end(); iter) {// errorif(*iter a) {vec.erase(iter);// error}}}std::list排序使用自己的成员方法一般的容器排序都使用std::sort()但是list特殊。12345678910intmain() {std::listint list{1, 2, 3, 2};list.sort();// std::sort(list.begin(), list.end());for(auto i : list) {std::cout i ;}std::cout \n;return0;}new/delete、new[]/delete[]、malloc/free严格配对这几个一定要配对使用原因的话可以看我之前的文章《new[]和delete[]为何要配对使用 》基类析构函数要是虚函数如果不是虚函数的话可能会有内存泄漏的问题注释用/**/而不是//注释用/**/可能会出问题。原因:utf-8和ANSC(GB2312)编码混乱后中文注释就乱码了乱码中藏着 */匹配错了导致IDE实际注释的部分并非肉眼所见定位极其困难常见于Windows中。成员变量初始化成员变量没有默认初始化行为需要手动初始化。不要返回局部变量的指针或引用1234char* func() {chara[3] {a,b,c};returna;}栈内存容易被污染。浮点数判断是否相等问题123floatf;if(f 0.2) {}// 错误用法if(abs(f - 0.2) 0.00001) {}// 正确用法vector clear和swap问题清空某个vector可以使用swap而不是其clear方法这样可以更早的释放vector内部内存。123vectorint vec;vectorint().swap(vec);vec.clear();vector问题尽量不要在vector中存放bool类型vector为了做优化它的内部存放的其实不是bool。条件变量条件变量的使用有两大问题信号丢失和虚假唤醒相当重要具体可以看我这篇文章《使用条件变量的坑你知道吗》。类型转换在C中尽量使用C风格的四种类型转换而不要使用C语言风格的强制类型转换。异步操作中async的使用12std::async(std::launch::async, []{ f(); });// 临时量的析构函数等待 f()std::async(std::launch::async, []{ g(); });// f() 完成前不开始std::async 这货返回的 future 和通过 promise 获取的 future 行为不同async 返回的 future 对象在析构时会阻塞等待 async 中的线程执行完毕这就导致在大部分场景中 async达不到你直觉的认为它能达到的目的。智能指针一个裸指针不要使用多个智能指针包裹尽可能使用make_uniquemake_shared。当需要在类得内部接口中需要将this作为智能指针使用需要用该类派生自enable_shared_from_this栈内存使用合理使用栈内存特别是数组数组越界问题容易导致栈空间损坏可以考虑使用std::array替代普通的数组。std::thread的使用一定要记得join或这detach否则会crash。12345678voidfunc() {}intmain() {std::threadt(func);if(t.joinable()) {t.join();// 或者t.detach();}return0;}enum使用尽量使用enum class替代enumenum class 是带有作用域的枚举类型。空指针使用nullptr而不是NULL123456789101112voidfunc(char*) {cout char*;}voidfunc(int) {cout int;}intmain() {func(NULL);// 编译失败 error: call of overloaded ‘func(NULL) is ambiguousfunc(nullptr);// char*return0;}std::remove的使用这个remove其实并没有真正的删除元素需要和erase配合使用跑一下这段代码就知道啦。12345678910111213141516171819202122boolisOdd(inti) {returni 1; }voidprint(conststd::vectorint vec) {for(constauto i : vec) {std::cout i ;}std::cout std::endl;}intmain() {std::vectorint v {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};print(v);std::remove(v.begin(), v.end(), 5);// errorprint(v);v.erase(std::remove(v.begin(), v.end(), 5), v.end());print(v);v.erase(std::remove_if(v.begin(), v.end(), isOdd), v.end());print(v);}全局变量初始化问题不同文件中的全局变量初始化顺序不固定全局变量尽量不要互相依赖否则由于初始化顺序不固定的问题可能会导致bug产生。