单独开一篇文章,之前零零散散的书评散落在笔记和微言中,没有具体辑录到一块,不方便索引。以后读过的技术类的书籍之后我会写一些评价就都放到这里来了。因为评价对象是技术书籍,只言片语也不能描述所有的技术细节,本文立意也非“技术笔记”而是“书籍评价”,所以我不会在这里涉及太多书籍中描述的技术细节,只是我作为一个普通读者的阅读感受以及分享我个人的阅读技巧,若其中对某些书透露出褒贬之意均为我个人对书籍的评价无任何贬低作者的意图。
特殊成员函数的隐式声明及其标准行为
在C++编程中比较痛恨欲绝的事莫过于:编译器瞒着程序员做了太多事。
本篇文章是从C++标准([ISO/IEC 14882:2014])中整理摘录出来的关于编译器生成类的默认构造函数(default constructor)
/拷贝/移动构造函数(copy/move constructor)
/拷贝/移动赋值操作符(copy/move assignment operator)
/析构函数(destructor)
这六个特殊成员函数的几种情况以及其实际行为的文档。可以作为《Inside The C++ Object Model》的辅助资料,组合观看效果更佳(通过标准描述来理解编译器的实现)。
另外,《Inside The C++ Object Model》主要是从“编译器实现”的角度来描述的,但是从“C++标准”的角度来看,书里很多是依赖于编译器实现的,就像虚函数表,标准并没有规定编译器应该用何种方式实现多态行为,自然也就不可能描述关于虚函数表的东西。
还有很多对于“编译器生成”的行为在主观意识中带有歧义的理解,都可以在这里找到解答,这也是读C++标准的乐趣所在——不论好坏,标准规定不会出错,所有不符合标准描述的实现都是unstandard的。
C++函数模板的特化和重载
不同于类模板,可以具有显式特化和局部特化(partial specializations),函数模板没有”局部特化”的概念,只有显式特化和重载。
C++中指向类成员的指针并非指针
“指向类成员的指针(Pointers to members)”,是一种在C++不常用的特性,但是这里使用术语“指针”略有不妥,因为它们并不包含地址,行为也不像指针。
本篇文章会通过LLVM-IR来分析clang中对于“指向类成员的指针”的实现方式,以及穿插C++14标准内定义的相关内容和涉及到的LLVM-IR的语法。
为什么需要extern "C"?
在上一篇文章(C/C++编译模型分析)中介绍了C和C++中编译和链接的成因和方式。接上篇文章的坑,本篇文章从extern "C"
着手分析C和C++编译与链接模型中的不同点及其成因,主要为function overload
、function signatures
、name mangling
三个部分。
C/C++编译和链接模型分析
C和C++均使用分离编译来支持多源文件模块化机制,但是为什么这么做以及如何做是个值得探讨的问题。本篇文章并非是讲述C和C++中如何才能产生不同链接的语法规则,而是分析下C/C++编译器是如何实现编译和链接模型的。
Array of length zero
看了下在C中Array of length zero
的用法,感觉脑洞大开啊。不过从标准角度(非编译器扩展)来说,这个特性只存在于C语言(C99之后),C++中是不存在的。先挖个坑,来分析一下。
虚拟存储器的缺页异常分析
考虑这样一个问题:能否通过管道(fifo)从一个进程A向另一个进程B(A和B之间并无亲属关系)中传递A进程中对象的地址,从而在进程B中访问到A进程的对象呢?
STL容器的迭代器失效
容器的大小指的是容器中的元素数目;容器的容量指的是重新分配更多内存之前容器能够保存的元素数目。在改变大小或容量时,元素可能会移动到新的存储位置。这意味着指向元素的迭代器(以及指针或引用)可能会失效(即指向旧元素的位置)。
指向关联容器元素的迭代器只有当所指元素从容器中删除时(erase)才会失效。与之相反,指向顺序容器元素的迭代器当重新分配空间(resize()
/reverse()
或push_back()
)或指向元素在容器中移动(如在前一个位置进行erase()
或者insert()
)也会失效。
通过IR代码来分析C++代码语义
IR代码是LLVM生成的Intermediate Code
。可以通过IR代码来分析编译器对我们所写的代码是如何解析并执行的,使得分析代码语义变得简洁明了。IR代码的语法语义可参考LLVM Language Reference Manual。