野史几则

· · 算法·理论

本文获得了 using namespace std; 的大力支持

  1. std::string 一直很嫉妒它的兄弟 std::vector<char>,因为后者被公认为“真正的容器”。它试图通过提供 push_backoperator[] 来模仿,但每当它不小心调用 .c_str() 时,就会暴露其底层 C 字符串的出身,羞愤难当。

  2. std::map 是个强迫症,家里一切都必须按红黑树严格排序。它的堂弟 std::unordered_map 则是个乱室佳人,东西扔得满地都是还声称“我知道它们在哪儿”。当 map 看到 unordered_map.find() 比自己快时,气得差点把树撕成了链表。

  3. std::optional 患有严重的选择困难症。每次有人问它“你有值吗?”,它都会陷入哲学思考:“我有吗?还是没有?这是一个问题……” std::variant 对此忍无可忍,一把抢过它手里的东西:“要么给我,要么滚蛋!”

  4. std::any 是个神秘的收藏家,什么都往肚子里塞。但当有人用 any_cast 问它要特定东西时,它总是支支吾吾。直到某天被强行剖开,大家发现里面除了一只臭袜子和过期的优惠券,什么都没有。

  5. std::thread 是个多动症,一生下来就到处乱跑。有一次它跑得太快,一头撞在墙上,变成了 std::this_thread::sleep_for,在走廊里睡了三天三夜。醒来后发现它的 CPU 时间片已经被其他线程瓜分了。

  6. std::atomic 患有量子叠加态综合征,总觉得自己同时是 0 和 1。医生给它开了 memory_order_seq_cst 的强效药,结果副作用是反应迟钝,每次改变状态都要通知全宇宙,累得气喘吁吁。

  7. std::regex 自称语言学家,其实是个严重结巴。你问它“你好吗?”,它得先念叨“你...你...你好...好吗...吗?” 十分钟。std::string_view 有一次实在受不了,直接把它从代码里 #include 扔了出去。[^1]

  8. std::filesystem::path 是个天生的路痴。它试图用 .parent_path() 找爸爸,结果顺着目录树往上爬了三代,发现祖先全是斜杠和圆点。最后它绝望地宣布:“我就是根目录!”,然后把自己变成了 "."

  9. std::coutstd::cin 是一对怨偶。一个喋喋不休说个不停,另一个耳背永远听不清。每次交流都得靠 std::endl 摔杯子来清空缓冲区,才能引起对方注意。std::cerr 看不下去,把它们都锁进了 std::ios_base::sync_with_stdio(false) 的小黑屋。

  10. <algorithm> 全家都是强迫症晚期。std::sort 见不得任何无序的东西,连别人家的衣柜都要整理;std::find_if 拿着放大镜到处寻找符合特定条件的物件;最可怕的是 std::rotate,经常把数组的头拧到屁股的位置上,还沾沾自喜。

  11. std::variant 是一个人格分裂者,体内住着多个不同的类型。它每次只能让一个人格出来活动,如果访客猜错了当前是谁主导,就会遭到 std::get 的暴力对待,被扔进 std::bad_variant_access 的深渊。[^2]

  12. std::chrono 是时间管理大师,但对“现在几点”这个问题有着近乎偏执的复杂定义。system_clocksteady_clockhigh_resolution_clock 整天吵架,争论谁才是“真正的现在”,导致 now() 函数每次回答都要犹豫半天。

  13. std::random_device 自称是真正的随机数之源,但其实家里穷得揭不开锅,在某些系统上只能拿伪随机数种子糊口。它的孩子们(各种分布器)对此一无所知,还在炫耀自己的“真随机”血统。 [^3]

  14. std::promisestd::future 是一对异地恋情侣。promise 在另一个线程里辛辛苦苦准备结果(set_value),而 future 在原地干等(wait),还动不动就发脾气(get),如果等不到结果就彻底崩溃。

  15. std::stringstreamstd::stringstd::iostream 的私生子。它既想当个高效的字符串,又想扮演华丽的流,结果两头不讨好,性能慢得像蜗牛,被全家人嫌弃。[^4]

  16. std::bitset 是一个二进制偏执狂,看世界非 0 即 1。它曾试图追求 std::vector<bool>,发现后者虽然也是二进制但行为怪异,伤心之下把自己锁在家里,天天对着 .to_string() 照镜子。

  17. std::tuple 是个收集癖,喜欢把各种不同类型的东西捆在一起。但当别人问它“你的第一个元素是啥?”时,它必须让 std::get<0> 这位管家来回答,自己根本记不住成员的顺序和名字。

  18. std::initializer_list 是个活在过去的家伙。它只能在对象刚出生时(构造函数里)献上自己的礼物,一旦对象长大,它就立刻失忆,再也记不起当初送了些什么。[^5]

  19. std::type_infotypeid 是鉴定科的兄弟,负责给所有类型发身份证。但它们发的身份证(type_info)既不能拷贝也不能自己创造,想知道是谁,必须把本人(变量)抓过来按在 typeid 上当场验明正身。

  20. std::common_type 是个和事佬,专门调解不同类型之间的“求同”问题。但当 intdouble 吵得不可开交时,它通常只会和稀泥地宣布:“你们都变成 double 吧!”,毫无新意 (fw)

  21. std::char_traitsbasic_string 家族背后的影子管家,默默负责所有字符的比对、拷贝和长度计算。功劳全是 string 的,黑锅却总是它背,比如为什么 std::string 没有 case_insensitive_compare。[^6]

  22. std::nth_element 是排序家族里的半吊子。它承诺“只给你部分排序”,但当别人要求它把第 N 个元素放到正确位置时,它总是把周围环境搞得一团糟,然后说:“看,你的元素在这儿了,别的就别管了!”[^7]

[^1]: std::regex 的编译和匹配性能确实是著名的槽点。

[^2]: std::variant 访问时必须知道当前存储的类型,否则会抛出异常。

[^3]: std::random_device 在某些平台上可能回退为伪随机数生成器。

[^4]: std::stringstream 因为涉及动态分配和流操作,性能通常不如直接操作字符串。

[^5]: std::initializer_list 的生命周期是暂时的,通常只在构造函数中有效。

[^6]: std::char_traits 确实定义了字符操作的默认行为,要改变比较规则需要特化它。

[^7]: std::nth_element 只保证第 n 个元素的位置正确,其左右两边的序列只是被划分,并非完全排序。