野史几则
zangjh6666 · · 算法·理论
本文获得了 using namespace std; 的大力支持
-
std::string一直很嫉妒它的兄弟std::vector<char>,因为后者被公认为“真正的容器”。它试图通过提供push_back和operator[]来模仿,但每当它不小心调用.c_str()时,就会暴露其底层 C 字符串的出身,羞愤难当。 -
std::map是个强迫症,家里一切都必须按红黑树严格排序。它的堂弟std::unordered_map则是个乱室佳人,东西扔得满地都是还声称“我知道它们在哪儿”。当map看到unordered_map的.find()比自己快时,气得差点把树撕成了链表。 -
std::optional患有严重的选择困难症。每次有人问它“你有值吗?”,它都会陷入哲学思考:“我有吗?还是没有?这是一个问题……”std::variant对此忍无可忍,一把抢过它手里的东西:“要么给我,要么滚蛋!” -
std::any是个神秘的收藏家,什么都往肚子里塞。但当有人用any_cast问它要特定东西时,它总是支支吾吾。直到某天被强行剖开,大家发现里面除了一只臭袜子和过期的优惠券,什么都没有。 -
std::thread是个多动症,一生下来就到处乱跑。有一次它跑得太快,一头撞在墙上,变成了std::this_thread::sleep_for,在走廊里睡了三天三夜。醒来后发现它的 CPU 时间片已经被其他线程瓜分了。 -
std::atomic患有量子叠加态综合征,总觉得自己同时是 0 和 1。医生给它开了memory_order_seq_cst的强效药,结果副作用是反应迟钝,每次改变状态都要通知全宇宙,累得气喘吁吁。 -
std::regex自称语言学家,其实是个严重结巴。你问它“你好吗?”,它得先念叨“你...你...你好...好吗...吗?” 十分钟。std::string_view有一次实在受不了,直接把它从代码里#include扔了出去。[^1] -
std::filesystem::path是个天生的路痴。它试图用.parent_path()找爸爸,结果顺着目录树往上爬了三代,发现祖先全是斜杠和圆点。最后它绝望地宣布:“我就是根目录!”,然后把自己变成了"."。 -
std::cout和std::cin是一对怨偶。一个喋喋不休说个不停,另一个耳背永远听不清。每次交流都得靠std::endl摔杯子来清空缓冲区,才能引起对方注意。std::cerr看不下去,把它们都锁进了std::ios_base::sync_with_stdio(false)的小黑屋。 -
<algorithm>全家都是强迫症晚期。std::sort见不得任何无序的东西,连别人家的衣柜都要整理;std::find_if拿着放大镜到处寻找符合特定条件的物件;最可怕的是std::rotate,经常把数组的头拧到屁股的位置上,还沾沾自喜。 -
std::variant是一个人格分裂者,体内住着多个不同的类型。它每次只能让一个人格出来活动,如果访客猜错了当前是谁主导,就会遭到std::get的暴力对待,被扔进std::bad_variant_access的深渊。[^2] -
std::chrono是时间管理大师,但对“现在几点”这个问题有着近乎偏执的复杂定义。system_clock、steady_clock和high_resolution_clock整天吵架,争论谁才是“真正的现在”,导致now()函数每次回答都要犹豫半天。 -
std::random_device自称是真正的随机数之源,但其实家里穷得揭不开锅,在某些系统上只能拿伪随机数种子糊口。它的孩子们(各种分布器)对此一无所知,还在炫耀自己的“真随机”血统。 [^3] -
std::promise和std::future是一对异地恋情侣。promise在另一个线程里辛辛苦苦准备结果(set_value),而future在原地干等(wait),还动不动就发脾气(get),如果等不到结果就彻底崩溃。 -
std::stringstream是std::string和std::iostream的私生子。它既想当个高效的字符串,又想扮演华丽的流,结果两头不讨好,性能慢得像蜗牛,被全家人嫌弃。[^4] -
std::bitset是一个二进制偏执狂,看世界非 0 即 1。它曾试图追求std::vector<bool>,发现后者虽然也是二进制但行为怪异,伤心之下把自己锁在家里,天天对着.to_string()照镜子。 -
std::tuple是个收集癖,喜欢把各种不同类型的东西捆在一起。但当别人问它“你的第一个元素是啥?”时,它必须让std::get<0>这位管家来回答,自己根本记不住成员的顺序和名字。 -
std::initializer_list是个活在过去的家伙。它只能在对象刚出生时(构造函数里)献上自己的礼物,一旦对象长大,它就立刻失忆,再也记不起当初送了些什么。[^5] -
std::type_info和typeid是鉴定科的兄弟,负责给所有类型发身份证。但它们发的身份证(type_info)既不能拷贝也不能自己创造,想知道是谁,必须把本人(变量)抓过来按在typeid上当场验明正身。 -
std::common_type是个和事佬,专门调解不同类型之间的“求同”问题。但当int和double吵得不可开交时,它通常只会和稀泥地宣布:“你们都变成double吧!”,毫无新意(fw)。 -
std::char_traits是basic_string家族背后的影子管家,默默负责所有字符的比对、拷贝和长度计算。功劳全是string的,黑锅却总是它背,比如为什么std::string没有case_insensitive_compare。[^6] -
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 个元素的位置正确,其左右两边的序列只是被划分,并非完全排序。