败犬日报 2024-10-22
1. 一个库申请的内存到另一个库释放,发生了崩溃
谁申请谁释放,这个原则可以规避这类问题。
我们来分析一下为什么崩溃:
内存申请释放一般走 glibc / musl 之类的库。
glibc 这样的库,它的 malloc 依赖它里面定义的全局变量状态;这样的全局变量出现多份就会出现上述问题。
不光是 malloc,别的函数比如 fopen 这种分配句柄的,都得一个全局的变量(状态)来记录已经分配的内存 / 句柄。把 A 变量分配的 handle 交给 B 变量释放,就会 crash。
根本原因是 ODR 违背导致的,跨动态库使用变量导致 crash。
所以问题就变成,静态链接 / 动态链接的符号可见性以及符号合并的情况了。要想知道啥时候链接器不合并,就去查动态库符号可见性;静态链接符号合并规则和动态链接符号合并规则不同。
模板隐式实例化也会有类似问题。动态库和主程序各一份实例化(实例化的时候只能看见自己的 malloc free 啥的),而且未合并。
值得注意的是,隐式实例化在静态链接的时候一定是会合并的,但是动态链接的时候则情况非常复杂了。
扩展阅读:https://zhuanlan.zhihu.com/p/692886292
2. 关于异步函数调用的场景
async_handle handle = some_operation();
// do something async
async_wait(handle);
每个核只跑一个线程,也没有线程池啥的,通过双缓冲实现计算和 IO 异步并行。
cpu 提一个 io 任务,交给 io 硬件 (dma 之类的) 完成,然后同时 cpu 去计算上次提交 io 读进来的东西。
等这边计算完了,差不多下次 IO 的数据也准备好了。
muduo 的日志部分好像也有用到双缓冲流水。
3. 计算机的哪些学科是被建议在本科阶段学掉的?
对于 https://www.zhihu.com/question/595969891/answer/3054501672 的锐评:
- 抛开目的谈意义没道理,应该看你想做什么再去学习什么。
- 我觉得大体还是有道理的,就是觉得他对语言的认知太偏颇了。
- 都说了骂律师是顺嘴的事了。
- 解构适合有一定水平的一群人合作,抽象适合水平一般的一群人合作。知道细节可以一个人更快,屏蔽细节可以一群人更快。
4. 一个 byte 应该是几个 bit
绝大部分环境是 8。
5. 参数包下标访问这个东西,为什么不是刚发明参数包这个语法的时候或者下一个版本就有的
因为 cpp 特有的 workaround,能实现就不着急进。
又不是不能用.jpg
6. 给类加个前置声明,声明和定义按标准必须都写相同的约束
是的。
7. 什么时候才能不用写前置声明
去掉前置声明,不论在前面还是在后面都可用,这个事情在技术上有什么困难吗?
编译用时++
8. 约束模板类的重载
template <concept1 T>
struct A {};
template <concept2 T>
struct A {};
其中 concept2 比 concept1 更严格。
这是重定义。
如果第二个改成:
template <concept2 T>
struct A<T> {};
可以,见 https://en.cppreference.com/w/cpp/language/function_template#Function_template_overloading