Skip to content

败犬日报 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. 关于异步函数调用的场景

cpp
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 的锐评:

  1. 抛开目的谈意义没道理,应该看你想做什么再去学习什么。
  2. 我觉得大体还是有道理的,就是觉得他对语言的认知太偏颇了。
  3. 都说了骂律师是顺嘴的事了。
  4. 解构适合有一定水平的一群人合作,抽象适合水平一般的一群人合作。知道细节可以一个人更快,屏蔽细节可以一群人更快。

4. 一个 byte 应该是几个 bit

绝大部分环境是 8。

5. 参数包下标访问这个东西,为什么不是刚发明参数包这个语法的时候或者下一个版本就有的

因为 cpp 特有的 workaround,能实现就不着急进。

又不是不能用.jpg

6. 给类加个前置声明,声明和定义按标准必须都写相同的约束

是的。

7. 什么时候才能不用写前置声明

去掉前置声明,不论在前面还是在后面都可用,这个事情在技术上有什么困难吗?

编译用时++

8. 约束模板类的重载

cpp
template <concept1 T>
struct A {};

template <concept2 T>
struct A {};

其中 concept2 比 concept1 更严格。

这是重定义。

如果第二个改成:

cpp
template <concept2 T>
struct A<T> {};

可以,见 https://en.cppreference.com/w/cpp/language/function_template#Function_template_overloading