准备
- 三大编译器: vs、gcc(gcc.gnu.org)、clang(www.llvm.org)
- 安装 gcc:
sudo apt-get install g++
然后按两下talbe
看看有哪些版本,选择最新的安装。 - 增加 update 更新库:
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
。g++ 安装失败有可能需要这样添加。 - 查看 gcc 版本:
gcc --version
。注意:如果自己选择安装了与默认不同的版本,则需要输入gcc-8 --version
查看。 - 安装 make:
sudo apt-get install make
。相比于windows环境下 VS 的工程创建不一样,linux 下必须要自己 make。规则本身简单,但是要写得好的话比较繁锁。(.h 文件修改要保持 make 更新的话,就需要在 makefile 文件中添加大量的 .h) - 编写 makefile:
hello:hello.o
g++ -o hello hello.o
hello.o:main.cpp
g++ -c -o hello.o main.cpp
四行拼起来。 - **安装 cmake:**手写 makefile 太复杂,用一些更高级的包装软件。
关键字
- 代替键盘上的字符:
and
、and_ep
、bitand
、bitor
、compl
、not
、not_eq
、or
、or_eq
、xor
、xor_eq
。 - constexpr: 编译期间能确定函数的返回值,直接用该值优化。
- const_cast:
const int j = 3; int *p = const_cast<int*>(&j); *p = 4;
有坑不要往里跳,代码中出现这种情况,说明设计有一定的问题。 - decltype: (declared type)
decltype(a->x) y; // 类型和a->x一样。
、decltype((a->x)) z = y; // y的引用。
表面看起来还没有auto好用。实际上是和auto一起用于模板编程中template<typename T, typename U> auto add(T a, U b) -> decltype(a+b) { return a+ b; }
后置返回类型。 - dynamic_cast: 去除动态转换。指针转换失败可以用是否为空来判断,但引用转换失败则会抛出异常。在C类cast、static_cast、const_cast中效率最低,但正确性最高(在运行期会做检查)。
- enum: 不受命名空间限制,容易冲突。所以以前的代码习惯性会在变量名中加自己的前缀。而且它的大小是根据实现决定的。
- enum class: 增加了命名空间限制,使用起来就像类一样。还可以自定义取值范围。
enum class NewColor : char { Red, Green, Blue };
之前说的接口参数不建议用bool类型,此时就可以用enum class替代。 - explicit: 增强明确性。个人见解,不要怕麻烦,能用则用。
- export: 比较尴尬。只有一款不流行的编译器实现了这个功能。Java编译器开发者,两三个人就能完成。两个顶尖计算机科学家花了两年也没有实现。C++11明确指出export基本不用了。
- friend: 很少用到。
- goto: 功能过于强大,基本不用。
- namespace: 未命名的namespace只能在本文件中使用,类似于static全局变量。
- noexcept(C++11起): 承诺函数不抛出异常,便于编译器优化。后面还可带括号
void f(int) noexcept(false) {}
。和以前的void f(int) throw() {}
一样。不太建议使用,需要像标准库一样严谨。 - nullptr(C++11起): 是一种类型,用于模板编程中固定为指针类型,如果是传入0或者NULL,模板是识别不出来指针类型的,nullptr就省略了(int*)0强转这一步。
- operator: 便于库的编写者用处比较大一些,对于普通C++程序员最好不用,带来的坏处比带来的好处还要多一些。
- register: 定义的变量放到寄存器里(建议编译器),提高速度。现在基本不用。
- reinterpret_cast: 几种cast总结:相对于C风格cast意图和分工更明确。除dynamic_cast以外,其他的都可以用C风格代替。建议使用C++版本的。
- requires(概念TS): C++17可能会用到。
- **static_assert:**编译时期确定。assert 是在运行时期确定的。
类
三个基本法则
- 资源管理: Java不需要手动释放只是说内存,除此之外还有文件句柄,网络连接。
- 三法则: 如果需要自己管理资源。析构函数、复制构造函数、赋值运算符。如果确实不需要复制对象,(C98中将复制构造函数、赋值运算符声明为private,但不实现它,链接时检查)(C++11中可以在private声明中 = delete,编译时检查)(继承boost::noncopyable可以省去写代码)
- C++诟病: 太多的复制。
vector<int> v = makeVector();
创建了临时变量,有没有办法将它利用起来。(C++采取了右值引用) - 左值和右值: 名字、类型、值。能取地址的通常是左值。右值无法取地址。
- 右值引用: 以前引用必须是可取地址的,
int& la = 1;
是错误的,但引入右值引用后int&& ra = 1;
可以。 - 新法则: 利用右值引用可以重载复制构造函数和赋值运算符。
- std::move(b): 将括号中的元素变换为右值。目的是把部分资源从右边直接移动到左边来(C++11之前没有区别)。因为对于右值来说,通常是临时变量,移交所有控制权。移交后的对象是完整的,但资源被抽干了,可以使用,但是不建议。
- 右值转换: 右值可以转换为const引用。
print(const int& a); print(1);
- delete规则: delete空指针没有问题,但是delete两次非空指针是会出问题的。
40、虚函数遇到构造析构就退化了
- 面向对象: 1、数据的封装;2、类的继承;3、函数的多态。
41、重新审视 auto
- 类型推导: 自动推导 = 号右边的数据类型,包括值和指针。
- range for: 自动遍历。优点是书写简单,运行效率高。缺点是必须全部遍历,没办法选取一半。
42、左值引用和右值引用(不考虑模板)
- 花括号构造: 更方便。但不允许有编译警告的值转换。比如 double 转 int 。
- 类成员初始化: 可以直接在定义的地方赋值。书写简单,不容易漏掉。如果不需要特殊的初始化,也要习惯地用默认值初始化,现在就可以用
int m_value {};
即可。 - 构造转发: 没有用到,所以没讲。
- 右值引用: 值可以改变。
int&& a = 10; a = 20;
。 - 右值引用: 不能直接等于左值,需要借助
std::move()
。
45、用 weak_ptr 打破循环引用
- 初始化: 用智能指针对象初始化。
- lock():
auto p = weakObj.lock();
如果有其它引用技术,则增加一份引用技术,返回智能指针对象,否则返回空。 - 重置: 当引用的对象调用 reset() 之后,就过期了。
- expired(): 是否过期(不会生成引用技术)。