技术: C++最终篇

以后全部的C++文章就在这里落脚了, C++17也在这里更新.

这里集中说一说, 就当汇总吧; 以后C++更新的新内容全部在此. 更新列表, 如下:

时间 内容
2017-8-26 初稿:C++标准文档
2017-9-14 更新:C++17新特性(参考《程序员杂志》,2017.09期)
2017-10-03 技术就是条无底洞, 尤其C++, 我不了解的内容还有很多; 遂修改部分言论

在今天这语言百花齐放的年代, C++标准的制定又被资金限制推迟, 一直是在追着时代跑(已经完全不能领先于时代了)

post-cover

C++的著作, 非常多, 鱼龙混杂. 我当年走了不少弯路; 实际上很多书可以不读.

经典著作

我在最开始写 Modern C++ 的时候, 就推荐过好基本书, 这里在集中说一说.

入门我一共推荐了2本: (入门你看看《C++编程语言-十周年版》也是不错的, C++本加尼写的)

  • 《C++语言演化》
  • 《C++ Primer(5e)》 (不要看第四版)

我一共推荐4本C++的额外读物:

  • 《Effective Modern C++》
  • 《Effective C++ 第三版》(相比第二版有很多新东西)
  • 《More Effective C++》
  • 《Effective STL》

后面3本是经典, 需要细读.

由于我不是专门研究或者参与语法研究, 我其实不太喜欢语法来语法去, 也比较讨厌硬是把给个主题都写一遍的书, 比如《Think In C++》.
(纯粹的浪费大好的青春, 年华)

还有一些, 比如《Inside C++ Object Mode》, 我只能说, 如果你还在上学, 请务必读一读; 如果已经工作, 呵呵, 你好闲啊.

标准文档

C++真正正式公布的标准只有三个:C++98、C++03、C++11:

  • C++98是第一个正式的C++标准
  • C++03是在C++98上面进行了小幅度的修订
  • C++11则是一次全面的大进化(之前称C++11为C++0x,以为会在08~09年公布,没想到拖到了11年, 原因?缺钱啊)
    (你看它的标准文档就知道了, 前两个版本都是2.7M左右, C++11直接变成了14M)

    现在貌似C++17标准也快了, 据说9月就会去开会讨论啥的. 不过C++标准的跳票也没准, 就像官方所说的, 缺乏资金推动.

下面给出标准库的文档, 可以参考我的github库:
C++98 (1998年)
https://github.com/WizardMerlin/Gate/tree/master/appendix/98.pdf

C++03 (2003年)
https://github.com/WizardMerlin/Gate/tree/master/appendix/03.pdf

C++11 (2011年)
https://github.com/WizardMerlin/Gate/tree/master/appendix/11.pdf

如果有时间, 这些文档是值得好好读读的, 而且是一手资料

C++17

C++17是语言小修改(相对C++14,大概20几条)、标准库增加比较多(大概200多条)。

C++20将会是可以和C++11可以媲美的大发展。

程序员杂志上《深入应用C++11》的作者给出了介绍, C++17其实主要是把Boost已经运用成熟的特性, 比如any, optional, filesystem等引入.
还有一些简化代码的机制, 比如nested namespace, if init, dedution guide等; 当然还增加了并行算法.

下面挑选我认为比较有意义的, 记录一下.

来自Boost

类型擦除的三个:

  • std::any
  • std::optional
  • std::variant

其中, std::optional一般用于返回值(返回不确定值), 而std::any, std::variant则用于存储任意类型的值, 只是在转换回来时, std::any,
需要使用std::any_cast<类型>, 而 std::variant 则用 std::get即可, 当然你用std::visit(functor, arg)也可以.

std::filesystem
基本和boost中的一致, 用来处理文件和目录, 比如:

1
2
3
4
5
6
namespace fs = std::filesystem;
std::string path = "C:\\test";
for(auto& p : fs::directory_iterator("test"))
{
std::cout << p << std::endl;
}

简化代码

这里最显著的就是, 嵌套的命名空间, 例如C++11会这么写:

1
2
3
4
5
6
7
8
9
10
11
namespace A
{
namespace B
{
namespace C
{
struct Foo{};
//...
};
};
};

然后C++17就直接这么搞:

1
2
3
4
5
namespace A::B::C
{
struct Foo{};
//...
};

static_assert
原来的静态断言, 你必须制定错误提示, 现在不用了, 直接给单个参数就好了, 下面是对比

1
2
static_assert(false, "sth. wrong"); //C++11
static_assert(false); //C++17, let compiler do message

条件初始化
在if语句里面初始化相关判断的变量, 之后if代码块执行完毕, 自动析构; 多好. 直接看例子吧: (举锁的例子)

C++11我们这么写的一段代码:

1
2
3
4
5
6
7
8
9
std::mutex mtx;
std::vector<int> v;

{
std::lock_guard<std::mutex> lock(mtx);
if(v.empty()) {
v.emplace_back(1);
}
}

凸出来的一段{ }代码块, 好看么? 再看看C++17, 直接起飞:

1
2
3
4
5
6
7
std::mutext mtx;
std::vector<int> v;

if(std::lock_guard<std::mutex> lock(mtx); v.empty())
{
v.emplace_back(1);
}

演绎推导deduction guide
有人还是很羡慕 JAVA的菱形语法, 但是C++17可以直接省略泛型, 编译时会自动推导:

1
std::pair p(1,1.5);

直接推导为

1
std::pair<int, double> p(1, 1.5);

也就是说, 进行了隐式推导.

当然你可以去写显示推导表达式, 个人认为比较麻烦, 除非你在写框架, 需要定义大量模板

capture *this
lambda表达里面捕获外部的值, 以值传递的方式, 还是有的, 比如说, 在main线程里面, 你给A线程传递一个值, 这个时候传引用么? 可以么? 就怕真到A线程执行的时候, main线程已经改变这个值了, 要想保证A线程拿到的, 就是你main线程, 开启A线程时传递的值, 怎么办? 值传递啊.

1
2
[=, copy=*this]{}   //C++11
[=, *this]{} //C++17

还有一些其他的特性, 感觉小修补, 还不错.

算法部分

std::search算法, 有点类似std::find_first_of, 但是它比find_first_of 更加适用于查找子串, 因为这个算法是以子串整体为单位.

再有就是并行算法.

说并行算法, 我们说的最多的就是, 你开俩线程, 累加一个数组的前半部分和后半部分

现在有了并行算法, 比如你拿std::reduce这个并行算法, 代替原来的 std::accumulate 求和, 性能直接翻翻, 还多.

但是并行算法, 因为是标准指出的, 就看编译器怎么实现, 怎么去支持了…

其他

其他部分, 再说吧, 小修小补, 还行吧, 以后在说?

文章目录
  1. 1. 经典著作
  2. 2. 标准文档
  3. 3. C++17
    1. 3.1. 来自Boost
    2. 3.2. 简化代码
    3. 3.3. 算法部分
  4. 4. 其他
|