C++是最好的垃圾语言

平时遇到的琐碎的C++\text{C++}稀奇古怪的知识,稀奇古怪的邪道和稀奇古怪的黑魔法。

虽然C++\text{C++}麻烦得雅痞,但还是得靠它吃饭啊。

类型萃取和using\text{using}

注意using的适用范围,只能引命名空间,基类和枚举。

所以,如果想要进行类型萃取得到一些编译期常量,目前我能想到的办法只能是static constexpr

表达式的值类别

只是简单区分左值和右值是不够的。现代C++\text{C++}标准规定了55种值类别——泛左值,纯右值,亡值,左值,右值。

在这里挖个坑吧:来自cppreference的解释。在以后编写代码的时候,对于每个表达式都一定心里要清楚是什么值。

编译器不万能

如果有可能,还是拿去compiler explorer\text{compiler explorer}看看代码编译出来的汇编啥样。既然用上了C++\text{C++},对性能的起码追求是得有的。如果要看函数是否内联了,常量是否传播了,稠密的操作是否向量化了,都只有看最后的汇编才能看出来。而这一点,不同的编译器跑出来的优化很可能是有区别的。

举例子,我用迭代器封装了稠密向量的顺序访问,写了个向量点积,然后希望知道编译器把它优化成什么样了。

开启O3\text{O3}优化的情况下,gcc\text{gcc}MSVC\text{MSVC}都能自动内联,把迭代器给优化掉。但是其中gcc\text{gcc}并没有发现并行性,一个个傻算的,而MSVC\text{MSVC}发现了并行性,启用了SIMD\text{SIMD}优化。

如果把迭代器改成经典的指标循环,gcc\text{gcc}就会发现并行性(中间封装了一层重载运算符,被内联了)并且启用SIMD\text{SIMD}优化。

所以啊,这些东西还是得自个去试验。。。

智能指针和RAII\text{RAII}

一个基本原则:不要无脑替换,智能指针首先应该用于指明所有权和资源管理。

下面是在Effective Modern C++\text{Effective Modern C++}的建议:

优先考虑unique_ptr,它与裸指针有着几乎一样的效率和占用空间。

只不过它不允许共享,只有移动语义,写起来会有点碍事。看起来这一条和Rust里的内存管理也有点像。理论上讲,使用裸指针,unique_ptr配合STL已经能完成很多事情了,这一点可以参考这个知乎回答

核心就是,智能指针首先应该看成一种通过RAII\text{RAII}实现资源管理的手段,而不是一种替代裸指针的手段。

举个例子就是渲染器,渲染器里的大部分对象生命周期都是持续到渲染结束的,并且渲染器通常会有一个Scene对象。

如果我们使用Scene管理资源,那么被管理的对象之间基本上是可以随便使用裸指针的,因为它们的生命周期都不可能比Scene还要长。

于是在这种情况下没必要用shared_ptr(事实上也不能随便用,因为渲染器的对象之间存在大量的相互引用)。

另外还有一点就是许多STL\text{STL}容器也是RAII\text{RAII}的,如有可能也请尽量使用这些容器。无论如何,我们真的是在写Modern C++\text{Modern C++}!