一开始想看这本书,然后写一个完整的观后感的。随着慢慢读,发现其实是C++历史。不需要像写技术博客那样正式。就当是记录一下读后感。

原来一个语言的历史,是这么的精彩。

设计的初衷,设计背后的故事,还有在面对大环境的发展,语言的走向是如何被影响的。

按照老头子的说法,C++是一门偏向系统编程的通用编程语言。想让编程更加简单(maybe就是更依靠编译器,但个人感觉越来越臃肿了)

唉,奈何linus不同意将C++纳入内核

第一个十年

带类的 C

第二个十年

C++98开始已经感觉到开始去主动区分CC++了。开始引入一些C有但不够严谨的特性有意的去区分。

RAIIRTTI YYDS

C++的2006

C++ 最艰难的一年,哈哈哈

boost 推动了C++的发展

C++ 标准委员会

搞的好正式,好高级

C++ 社区选择了“半组织”的混乱

SG4 网络,目前处于休眠状态” 标准委员会也不干网络啊。。。。。。

“我们商定了三年的发布周期,Herb Sutter 补充建议,采用交替发行大版本和小版本的英特尔“滴答”模型。”

意外后果总是会出现的。

是更重要的问题。人们很容易在细节中迷失。我提出的走出这一困境的方法是,就建议的方向、提案的总体范围达成一致,然后从一个相对较小子集的详细设计和实现出发,以关键用例为指导前进。

C++11:感觉像是门新语言

内存模型 双重检查锁定优化 无锁编程 阻止线程运行完成的能力 简单的事情简单做 范围 for 移动语义 资源管理指针 初始化列表 nullptr constexpr 函数 原始字符串字面量 属性 改进对泛型编程的支持 lambda 表达式 变参模版 别名 tuple

autodecltype 的区别:

auto 是用来“声明变量”的类型推导工具,而 decltype 是用来“分析表达式”的类型查询工具。

当用于初始化或赋值的源对象马上就会被销毁时,移动就比拷贝要更好:移动操作只是简单地把对象的内部表示“窃取”过来。&& 表示构造函数是一个移动构造函数,Matrix&& 被称为右值引用。当用于模板参数时,右值引用的符号 && 被叫做转发引用,这是由 John Spicer 在 2002 年的一次会议上,同 Dave Abrahams 和 Howard Hinnant 一起提出的。(开始复杂了)

右值引用可以用于给现有类方便地添加移动语义。意思是说,拷贝构造函数和赋值运算符可以根据实参是左值还是右值来进行重载。当实参是右值时,类的作者就知道他拥有对该实参的唯一引用。

但 operator= 的实现不符合现代惯用法:一般要么把参数设为 clone_ptr p,这就成了一个可以同时适配拷贝或移动的通用赋值函数;要么在函数体内进行一次移动构造,先 clone_ptr temp(std::move(p)); 再 std::swap(ptr, temp.ptr);。否则,当传递的实参是 std::move 的结果(xvalue)而不是真正的临时对象(prvalue)时,代码的行为会不符合预期。

std::move(b) 不是把 b 销毁,而是把它转换成一个右值(准确地说,是一个 xvalue,即“将亡值”);

shared_ptr 是传统的计数指针:指向同一对象的所有指针共享一个计数器。

提高静态类型安全

依赖静态类型安全有两大好处:

  • 明确意图
    • 帮助程序员直接表达想法
    • 帮助编译器捕获更多错误
  • 帮助编译器生成更好的代码。

支持对库的开发

元编程支持

noexcept 规约

标准库组件

  • thread——基于线程和锁的并发
  • regex——正则表达式
  • chrono——时间
  • random——随机数产生器和分布

C++14:完成 C++11

数字分隔符

变量模板

主要是为了类型安全,感觉是为了替代宏

函数返回类型推导

template<typename T>
auto size(const T& a) { return a.size(); }

这种写法上的便利对于泛型代码中的小函数来说非常重要。但用户必须很小心,此类函数不能提供稳定的接口,因为它的类型现在取决于它的实现,而且在编译到使用这个函数的代码时,函数实现必须是可见的。

泛型lambda表达式

constexpr 函数中的局部变量

概念 (这玩意还是太抽象了,先不学了)

概念的早期历史

三个基本属性来支持泛型编程

  • 全面的通用性/表现力
  • 与手工编码相比,零额外开销
  • 规范化的接口

C++0x 概念

为什么在 C++17 中没有概念

错误处理 (其实也不知道为什么做的这么烂)

背景

繁琐的重复错误检查使代码变得混乱。使用错误码时,很难将程序的主要逻辑与错误处理区分开。程序的主线(业务逻辑)与大量奇怪和模糊的错误处理代码紧密耦合在一起。对于那些错误处理本身就是主要的复杂逻辑而言,这种基于错误返回码的处理方式可能会带来严重的问题。

C、C++、Java语言中异常处理机制浅析 简记c、c++、java异常处理机制的区别 c++与Java异常处理的比较

C++17:大海迷航

构造函数模板参数推导


//以前
pair<string,int> p0 (string("Hi!"),129); // 不需要推导
auto p1 = make_pair("Hi!"s,129); // p1 是 pair<string,int>
pair p2 ("Hi!"s,129); // 错误:pair 缺少模板参数

结构化绑定

int arr[3] = {1, 2, 3};
auto [a, b, c] = arr;

variant、optional 和 any

没有编译期和运行期的检查来确保这个地址仅被用作其真实、指代的类型。

解决不同场景下的“类型多样性”问题

并发

在 C++17 中,以下类型的加入极大地简化了锁的使用:

  • scoped_lock——获取任意数量的锁,而不会造成死锁
  • shared_mutex 和 shared_lock——实现读写锁

并行 STL

基本的想法是,为每个标准库算法提供一个额外参数,允许用户请求向量化和/或 多线程。例如: sort(par_unseq, begin(v), end(v)); // 考虑并行和向量化

文件系统

条件的显式测试

后面的c++20相关的就不看了,还不太成熟