工作中遇到的C++语言基础和常见错误
C++历史及标准
这里简单列一下C++
发展进程中的几次重大事件以及我常使用的典型特性,各个标准支持的具体细节可参阅ISO标准文档。
-
C With Classes
:支持C++基础语言特性,包括多态、异常处理、模板、命名空间等 -
C++98
:STL、RTTI、模板、异常处理及其它标准库实现 -
C++03
:修复C++98中的缺陷及支持TR1 -
C++11
:auto、range-for、rvalue、lambda、shared_ptr、concurrent -
C++14
:变量模板、多态lambda及增强的库实现 -
C++17
:折叠表达式、类模板实参推导 -
C++20
:<=>、协程、概念
参数传递与返回值
- 避免产生临时变量导致冗余性能开销
int setupMVAudioStream(std::string path); // BAD int setupMVAudioStream(std::string const& path); // GOOD
- 返回值为类对象时确定使用RVO特性
// 如果此时函数体实现编译器未使用RVO,则会出现冗余性能开销,BAD std::list<MVStreamOption*> generateMVStreamList(std::list<MVStreamOption*> *optionList); // 使用引用传递参数返回结果,不会出现冗余性能开销,GOOD void generateMVStreamList(std::list<MVStreamOption*>& outList, std::list<MVStreamOption*> *optionList);
- 函数具有返回类型时需明确给出返回值,避免外部使用错误的返回值或者函数无法正常执行结束
int EditorService::updateRenderStreams(FileStreamList &streamList) { // 执行一些操作,没有return语句或者存在多个可能无法执行到的非全局生存期return语句 if (condition) { return -1; // 当condition为false时不执行 } // BAD } // 始终应该存在一个函数内全局生存期的return语句,避免其它非全局生存期的return语句未执行 int EditorService::updateRenderStreams(FileStreamList &streamList) { // 执行一些操作,可能存在多个多生存期管理的return语句 if (condition) { return -1; // 当condition为false时不执行 } return 0; // GOOD }
- 返回类成员变量时应该返回引用或者常量引用或者指针
// BAD,调用unordered_map的拷贝构造函数导致额外性能开销 std::unordered_map<Node*, int> Node::GetActiveChildren() { return mActiveChildren; } // GOOD,返回引用和常量引用,不会产生临时对象 std::unordered_map<Node*, int>& Node::GetActiveChildren() { return mActiveChildren; } std::unordered_map<Node*, int> const& Node::GetActiveChildren() const { return mActiveChildren; }
基类声明虚析构函数避免产生内存泄漏
struct Base { // BAD: implicitly has a public nonvirtual destructor virtual void f(); }; struct D : Base { string s {"a resource needing cleanup"}; ~D() { /* ... do some cleanup ... */ } // ... }; void use() { unique_ptr<Base> p = make_unique<D>(); // ... } // p's destruction calls ~Base(), not ~D(), which leaks D::s and possibly more
构造和析构函数中避免调用虚函数
class Base { public: virtual void f() = 0; // not implemented virtual void g(); // implemented with Base version virtual void h(); // implemented with Base version }; class Derived : public Base { public: void g() override; // provide Derived implementation void h() final; // provide Derived implementation Derived() { // BAD: attempt to call an unimplemented virtual function f(); // BAD: will call Derived::g, not dispatch further virtually g(); // GOOD: explicitly state intent to call only the visible version Derived::g(); // ok, no qualification needed, h is final h(); } };
优先使用初始化列表而不是赋值构造对象
class B { // BAD string s1; public: B(const char* p) { s1 = p; } // BAD: default constructor followed by assignment // ... }; class C { // UGLY, aka very bad int* p; public: C() { cout << *p; p = new int{10}; } // accidental use before initialized // ... }; class D { // Good string s1; public: A(string_view v) : s1{v} { } // GOOD: directly construct // ... };
使用auto作为返回类型推导时增加cv修饰避免产生临时变量
std::unordered_map<Node*, int> const& Node::GetActiveChildren() const { return mActiveChildren; } // BAD: 此时children类型实际为std::unordered_map<Node*, int>,退化为采用模板类型推导没有cv属性 auto children = node->GetActiveChildren();
优先使用emplace接口替换push/insert提高性能
std::list<std::string> ls; std::string s("abc"); ls.push_back(s); // BAD ls.push_back(std::move(s)); // GOOD ls.push_back("abc"); // GOOD ls.emplace_back("abc"); // BETTER
使用make_unique/make_shared构造智能指针管理对象
// Not exception-safe: the compiler may interleave the computations of arguments as follows: // // 1. allocate memory for Foo, // 2. construct Foo, // 3. call bar, // 4. construct unique_ptr<Foo>. // // If bar throws, Foo will not be destroyed, and the memory-allocated for it will leak. f(unique_ptr<Foo>(new Foo()), bar()); // BAD // Exception-safe: calls to functions are never interleaved. f(make_unique<Foo>(), bar()); // GOOD
使用empty代码size判断STL容器是否为空
std::list<int> ls; // ... // BAD: 不同的STL标准实现稍有差异,比如Android下的list.size的时间复杂度为O(N) if (ls.size() > 0) { // ... } // GOOD:时间复杂度为O(1) if (!ls.empty()) { // ... }
总结
C++有很多特性,上述只是列出了极小一部分使用过程中经常出现问题的一些用法,比如导致崩溃或者内存泄漏等,以及可以使用性能更高的一些建议,更多的用法将在后续逐渐总结出来。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Express 的使用
以下内容,基于 Express 4.x 版本 Node.js 的 Express Express 估计是那种你第一次接触,就会喜欢上用它的框架。因为它真的非常简单,直接。 在当前版本上,一共才这么几个文件: lib/ ├── application.js ├── express.js ├── middleware │ ├── init.js │ └── query.js ├── request.js ├── response.js ├── router │ ├── index.js │ ├── layer.js │ └── route.js ├── utils.js └── view.js 这种程度,说它是一个“框架”可能都有些过了,几乎都是工具性质的实现,只限于 Web 层。 当然,直接了当地实现了 Web 层的基本功能
- 下一篇
golang下载gocolly/colly
git clone https://github.com/golang/net.git src/github.com/golang/netgit clone https://github.com/golang/sys.git src/github.com/golang/sysgit clone https://github.com/golang/tools.git src/github.com/golang/toolsgit clone https://github.com/golang/lint.git src/github.com/golang/lintgit clone https://github.com/golang/mod.git src/github.com/golang/modgit clone https://github.com/golang/text.git src/github.com/golang/textgit clone https://github.com/golang/crypto.git src/github.com/golang/crypto然后复...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS8安装Docker,最新的服务器搭配容器使用
- CentOS7安装Docker,走上虚拟化容器引擎之路
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Docker安装Oracle12C,快速搭建Oracle学习环境
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果