败犬日报 2024-10-16
1. std::mutex 应该用 RAII 不推荐手动 unlock()
因为如果上锁的部分中有比较复杂的控制流(例如异常),那还需要记得在控制流的每一个出口手动 unlock(),否则就会出问题。
C++ 中,几乎所有情况都不应该使用原始 mutex 的 lock / unlock,而用 lock_guard / unique_lock 等更高层次的封装代替。
2. 线程安全哈希表 benchmark
完整 benchmark 见 https://www.boost.org/doc/libs/develop/libs/unordered/doc/html/unordered.html#benchmarks_boostconcurrent_flat_map
boost 的项目足够新,后发优势,可以抄其他项目的优秀设计,flat_hashmap 性能可能是知名实现里最好的。
3. lambda 的捕获是发生在什么时候
auto GetCurrentTimeNanos = []() -> int64_t {
timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return ts.tv_sec * 1000000000ll + ts.tv_nsec;
};
auto func = [&, start_time = GetCurrentTimeNanos()]() {
int64_t end_time = GetCurrentTimeNanos();
};
cppref 没说明白,标准说明白了的,在 lambda 求值时(创建时)初始化捕获:https://eel.is/c++draft/expr.prim.lambda#capture-15
4. clang-tidy 报变量没有被使用过
用 [[maybe_unused]]
。
一个通用的查找方式:clang-tidy 报的这个 warning 是有一个代号的,直接搜这个,会看到 clang-tidy 的文档。
5. 有什么办法可以萃取获得 lambda 函数的返回值和参数列表吗
拿 lambda::operator()
萃取。
6. 浮点运算的常数折叠行为有差异吗
有。
https://github.com/llvm/llvm-project/issues/62479
7. std::vector 扩容系数 1.5 为什么比 2 好
我们知道,std::vector 在容量不够时会申请新的一块空间,这个空间大小 = 原来的大小乘以扩容系数。MSVC 是 1.5,GCC / Clang 是 2。
唯一正解:实测 1.5 比 2 性能好!
folly 文档是这么写的:1.5 不一定能实现内存复用,但存在复用的概率;而 2 不存在理论复用的可能。这里的内存复用是怎么一回事呢?
我们考虑一个简单的场景:不断给一个 vector push_back 操作。
假设一开始 vector 容量是 V,扩容系数 p,那么接下来的 n 次扩容容量分别是:
接下来一次扩容,会申请
考虑 n 趋向于无穷大:
但是实际上内存分配器行为并不是那样的,内存复用在大多数情况都没有说服力(内存分配器一般会把大小近似的内存块放一起,导致复用的内存几乎不可能是同一个 vector 扩容留下的)。
我们知道,扩容系数越小内存占用期望降低,内存利用率越高;扩容系数越大扩容次数变少,扩容开销降低。之所以后来的很多设计采用了 1.5 而不是 2,因为 1.5 是两种因素的平衡点,是从大量实践中找到的。https://groups.google.com/g/comp.lang.c++.moderated/c/asH_VojWKJw?pli=1
关于 GCC 扩容系数为什么用 2:可能 GCC 实现太早了,没有意识到 1.5 更好。
相关阅读
- https://stackoverflow.com/questions/1100311/what-is-the-ideal-growth-rate-for-a-dynamically-allocated-array
- https://stackoverflow.com/questions/45403052/when-does-a-stdvector-enlarge-itself-when-we-push-back-elements
- https://www.zhihu.com/question/36538542/answer/67994276
8. realloc 是一个糟糕的设计
没时间读了先放这