Effective C++ notes

Effective C++ 笔记 0 导言 1 构造函数 default 构造函数:可被调用而不带任何实参的构造函数,这样的构造函数要么没有参数,要么每个参数都带有默认值,例如 class Bar { public: // explicit Bar(); // 是 default 构造函数 // explicit Bar(int x = 0) // 不是 default 构造函数 explicit Bar(int x = 0, bool b = true); // 是 default 构造函数 private: int x; bool b; }; explicit 关键字:阻止执行隐式类型转换,其优点是禁止了编译器执行非预期的类型转换,例如 void Foo(Bar obj); // Foo 函数的参数是一个类型为 Bar 的对象 Bar obj_1; // 构造一个 Bar 类型的对象 Foo (obj_1); // 没问题,传递一个 Bar 类型的对象给 Foo 函数 Foo (Bar()); // 没问题,构造一个 Bar 类型的对象,并传递给 Foo 函数 Foo (2); // 如果 Bar 的构造函数没有被声明为 explicit,那么会调用 Bar 的构造函数构造一个成员变量 x = 2 的对象,也就是说发生了隐式类型转换;如果其构造函数被声明为 explicit,那么就不会构造出 Bar 类型的对象 copy 构造函数:用同类型的对象初始化新的对象,它定义了一个对象如何 pass by reference。 ...

September 24, 2020 · 6 min

boost::typeIndex 的相关探究

boost::typeIndex 的相关探究 Effective Modern C++ 的 Item 4: Know how to view deduced types. 中提到了 Boost::typeindex 的使用,但并没有讲到其实现原理。 1. typeid 操作符 typeid 是 C++ 中的一个操作符,可以用于获取类型的信息,常常用在必须知道多态对象的动态类型,或是识别静态类型的地方。 我们可以写一个简单的 demo 用于获取对象类型相关的信息,需要包含 tepyinfo 头文件: #include <iostream> #include <typeinfo> using namespace std; class Foo {}; int main() { cout << "1: " << typeid(1).name() << endl; cout << "int: " << typeid(int).name() << endl; // 和 sizeof 操作符类似,typeid 也可以直接对数据类型(比如 int)进行操作 cout << "typeid: " << typeid(typeid(int)).name() << endl; cout << "typeid: " << typeid(const type_info &).name() << endl; const Foo *foo = new Foo(); cout << "foo: " << typeid(foo).name() << endl; cout << "*foo: " << typeid(*foo).name() << endl; cout << "Foo: " << typeid(Foo).name() << endl; } [joelzychen@DevCloud ~/typeid]$ g++ -std=c++11 -otypeid_test typeid_test.cpp [joelzychen@DevCloud ~/typeid]$ ./typeid_test 1: i int: i typeid: N10__cxxabiv123__fundamental_type_infoE typeid: St9type_info foo: PK3Foo *foo: 3Foo Foo: 3Foo std::type_info::name() 函数返回的字符串中,在 GCC 和 Clang 的实现里一般 i 代表 int,P 代表 pointer,K 代表 const,数字用于标识其后跟随了几个字符;我们可以将这段代码使用微软的 MSVC 编译运行,得到更加直观的输出: ...

July 31, 2020 · 6 min

CMake 入门

CMake 入门 0. 序 CMake 是一个跨平台的开源构建工具,使用 CMake 能够方便地管理依赖多个库的目录层次结构并生成 makefile 和使用 GNU make 来编译和连接程序。 1. 构建单个文件 1.1 使用 GCC 编译 假设现在我们希望编写一个函数来实现安全的 int 类型加法防止数据溢出,这个源文件没有任何依赖的源码或静态库: // safe_add.cpp #include <iostream> #include <memory> #define INT_MAX 2147483647 #define ERROR_DATA_OVERFLOW 2 int SafeIntAdd(std::unique_ptr<int> &sum, int a, int b) { if (a > INT_MAX - b) { *sum = INT_MAX; return ERROR_DATA_OVERFLOW; } *sum = a + b; return EXIT_SUCCESS; } int main() { int a, b; std::cin >> a >> b; std::unique_ptr<int> sum(new int(1)); int res = SafeIntAdd(sum, a, b); std::cout << *sum << std::endl; return res; } 我们可以直接使用一句简单的 gcc 命令来编译这个文件并执行: ...

June 21, 2020 · 11 min

GDB 调试入门

GDB 调试入门 0. 序 调试程序是开发过程中必不可少的一环,在 Windows 或 MacOS 上开发时,可以使用 VS 和 CLion 等 IDE 上自带的调试功能来打断点或查看变量和堆栈,但 Linux 并没有图形化的操作界面,而如果只通过打 log 的方式来查找问题的话效率将会非常低下,此时我们可以利用 GDB 来提升我们的开发效率。 GDB 是 GNU Debugger 的简写,是 GNU 软件系统中的标准调试器。GDB 具备各种调试功能,包括但不限于打断点、单步执行、打印变量、查看寄存器、查看函数调用堆栈等,能够有效地针对函数的运行进行追踪和警告;使用 GDB 调试时,可以监督和修改程序的变量,并且这些修改是独立于主程序之外的。GDB 主要用于调试编译型语言,对 C,C++,Go,Fortran 等语言有内置的支持,但它不支持解释型语言。 1. 环境搭建 1.1 编写程序 为了进行调试,我们需要准备一个简单的 C++ 程序: $ cat test.cpp #include <iostream> void Func(const char *s) { int *p = nullptr; int &r = static_cast<int&>(*p); int num = std::atoi(s); r = num; printf("%d\n", r); } int main (int argc, char *argv[]) { if (argc != 2) { printf("test [int]\n"); return -1; } Func(argv[1]); return 0; } 1.2 编译 对于 C/C++ 程序,在使用 gcc/clang 编译的时候需要加上参数 -g,才能生成完整的调试信息并在 GDB 中调试: ...

April 22, 2020 · 5 min

coverity 的 WRAPPER_ESCAPE 告警

coverity 的 WRAPPER_ESCAPE 告警 const char* Foo() { std::string str_msg("test"); return str_msg.c_str(); } int main() { const char *p_msg = Foo(); printf("%s\n", p_msg); return 0; } // output:(为空,或乱码) D? 上面代码中的 Foo 函数会被 coverity 报告 WRAPPER_ESCAPE,详细说明是: Wrapper object use after free (WRAPPER_ESCAPE) 1. escape: The internal representation of local strMsg escapes, but is destroyed when it exits scope 大意是局部变量 str_msg 在离开函数 Foo 的时候会被释放(因为 str_msg 是分配在栈上的变量),而通过函数 std::string::c_str() 获取的指向 str_msg 头部的指针会因此变为一个悬空指针,将这个悬空指针返回给函数调用者使用将会发生不可预知的行为。 而 c_str() 本身返回的是一个 const char *p,虽然我们无法直接修改指针 p 所指向的数据,但我们可以通过修改 str_msg 来达到修改 p 所指向内存的效果,例如如下的代码: ...

March 15, 2020 · 1 min