C++ 从入门到放弃?本文主要总结了在C++开发或review过程中常见易出错点做了归纳总结 , 希望借此能增进大家对C++的了解,减少编程出错,提升工作效率,也可以作为C++开发的避坑攻略 。空指针调用成员函数会crash??当调用一个空指针所指向的类的成员函数时 , 大多数人的反应都是程序会crash 。空指针并不指向任何有效的内存地址,所以在调用成员函数时会尝试访问一个不存在的内存地址 , 从而导致程序崩溃 。
事实上有点出乎意料,先来看段代码:
class MyClass {public: static void Test_Func1() { cout << "Handle Test_Func1!" << endl; } void Test_Func2() { cout << "Handle Test_Func2!" << endl; } void Test_Func3() { cout << "Handle Test_Func3! value:" << value << endl; } virtual void Test_Func4() { cout << "Handle Test_Func4!" << endl; } int value = 0;};int mAIn() { MyClass* ptr = nullptr; ptr->Test_Func1(); // ok, print Handle Test_Func1! ptr->Test_Func2(); // ok, print Handle Test_Func2! ptr->Test_Func3(); // crash ptr->Test_Func4(); // crash return 0;}
上面例子中,空指针对Test_Func1和Test_Func2的调用正常,对Test_Func3和Test_Func4的调用会crash 。可能很多人反应都会crash,实际上并没有,这是为啥?类的成员函数并不与具体对象绑定 , 所有的对象共用同一份成员函数体,当程序被编译后,成员函数的地址即已确定,这份共有的成员函数体之所以能够把不同对象的数据区分开来,靠的是隐式传递给成员函数的this指针 , 成员函数中对成员变量的访问都是转化成"this->数据成员"的方式 。因此,从这一角度说,成员函数与普通函数一样,只是多了this指针 。而类的静态成员函数只能访问静态成员变量,不能访问非静态成员变量,所以静态成员函数不需要this指针作为隐式参数 。
因此,Test_Func1是静态成员函数,不需要this指针,所以即使ptr是空指针,也不影响对Test_Fun1的正常调用 。Test_Fun2虽然需要传递隐式指针 , 但是函数体中并没有使用到这个隐式指针,所以ptr为空也不影响对Test_Fun2的正常调用 。Test_Fun3就不一样了 , 因为函数中使用到了非静态的成员变量,对num的调用被转化成this->num,也就是ptr->num,而ptr是空指针 , 因此会crash 。Test_Fun4是虚函数,有虚函数的类会有一个成员变量,即虚表指针,当调用虚函数时,会使用虚表指针,对虚表指针的使用也是通过隐式指针使用的,因此Test_Fun4的调用也会crash 。
同理,以下std::shared_ptr的调用也是如此,日常开发需要注意,记得加上判空 。
std::shared_ptr<UrlHandler> url_handler;...if(url_handler->IsUrlNeedHandle(data)) { url_handler->HandleUrl(param);}
字符串相关字符串查找对字符串进行处理是一个很常见的业务场景,其中字符串查找也是非常常见的,但是用的不好也是会存在各种坑 。常见的字符串查找方法有:std::string::find、std::string::find_first_of、std::string::find_first_not_of、std::string::find_last_of,各位C++ Engineer都能熟练使用了吗?先来段代码瞧瞧:bool IsBlacklistDllFromSrv(const std::string& dll_name) { try { std::string target_str = dll_name; std::transform(target_str.begin(), target_str.end(), target_str.begin(), ::tolower); if (dll_blacklist_from_srv.find(target_str) != std::string::npos) { return true; } } catch (...) { } return false;}
上面这段代码,看下来没啥问题的样子 。但是仔细看下来,就会发现字符串比对这里逻辑不够严谨,存在很大的漏洞 。std::string::find只是用来在字符串中查找指定的子字符串 , 只要包含该子串就符合,如果dll_blacklist_from_srv = "abcd.dll;hhhh.dll;test.dll" 是这样的字符串 , 传入d.dll、hh.dll、dll;test.dll也会命中逻辑,明显是不太符合预期的 。
推荐阅读
- 沙滩裤最常见的面料有哪些 沙滩裤首选什么面料
- 7种常见水果,秋天吃正是好时候,健康促消化对吗
- 常见鸟类的本领和特征 常见鸟类的本领
- 八个 C++ 开源项目,帮助初学者进阶成长
- 买车分期与全款:内行揭秘,新手购车避坑指南
- 常见泵原理图 泵的结构与原理图
- U盘使用过程中常见问题及其解决方案
- SSL协议是什么?关于SSL和TLS的常见问题解答
- 衣服的常见面料,十大常见服装面料优缺点分析
- C++多线程编程:解锁性能与并发的奥秘