诗盗·天行日月

《#诗盗#·天行日月》:白首方知友难交,一意逍遥,钱袋飘飘;十岁春风稣不晓,一心求道,人间邈邈。

注解

改编自霹雳角色“天迹”的诗号。

仙衣眠云碧岚袍,一襟潇洒,两袖飘飘;
玉墨舒心春酝瓢,行也逍遥,坐也逍遥。

  • 天行日月:时间飞逝

诗盗·不算计·咏社

《#诗盗#·不算计·咏社》:风雨财源归,挨踢寒冬到。已是高僧绝尘心,犹有一诗骚。骚也不挣钱,只报暖春遥。待到资本卷死时,社在丛中笑。

注解

改编自近代伟人毛泽东的《卜算子·咏梅》。

风雨送春归,飞雪迎春到。已是悬崖百丈冰,犹有花枝俏。
俏也不争春,只把春来报。待到山花烂漫时,她在丛中笑。

  • 高僧绝尘心:当稣有“是非成败转头空,青山依旧在,几度夕阳红。”的领悟和境界时,总有人提醒“你是穷逼”啊。稣内心一骚,总不能暴露稣存款千万的秘密吧!

  • 社在丛中笑:财源是资本主义的报复行为……社会主义接班稣早就看穿这险恶的招数,社会主义必将笑到最后。

诗盗·财源与君

《#诗盗#·财源与君》:财源与君君自宽,挨踢翻覆似波澜。白首相知犹内卷,朱门先达笑弹冠。校招全经高薪稀,倒挂欲动冬风寒。绩效浮云何足问?不如卧槽且加班。

注解

改编自唐代诗人王维的《酌酒与裴迪》:

酌酒与君君自宽,人情翻覆似波澜。
白首相知犹按剑,朱门先达笑弹冠。
草色全经细雨湿,花枝欲动春风寒。
世事浮云何足问,不如高卧且加餐。

  • 朱门:这里特指资本家。

  • 高薪稀:每年校招工资上限都提高,而且大肆宣传,但其实都是一个广撒网的套路,一段时间后,公司发现新人能力不够时,很容易被裁掉。高回报高风险。

  • 卧槽:卧在一个槽里,与“跳槽”相对。

现代 C++【3】返回类对象

前提

多现代?C++ 11 就有了。

问题

我想返回一个对象,但我受到惊吓……

是不是应该从指针型参数返回对象?

结论

已经 C++20 了,请放心,直接,返回对象!

概念

  • RVO:Return Value Optimization,返回值优化。

广义的 RVO 分为两种,它们之间的主要区别在于返回值是具名的局部变量还是无名的临时对象。

  1. NRVO:Named RVO,具名的返回值优化。这是可选的优化,通常没有多个返回路径返回不同的对象,或者返回的对象不依赖于条件判断时,会被实施。

  2. URVO:Unnamed RVO,匿名的返回值优化。通常 RVO 特指 URVO。C++ 17 开始 URVO 必然被实施。

返回的对象会 move 给接收的变量,并且,最多可能优化成直接对接收变量进行构造(NRVO)。

如果明确没有 move 构造函数,则会调用 copy 构造函数,当对象构造代价高时,应该尽量保证有 move 构造函数。

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 传统,不建议,可读性差,使用也不方便
void GetName(std::string& name) noexcept {
name = "UMU";
}

// URVO,C++ 17 开始必然优化
std::string GetName() noexcept {
return "UMU618";
}

// NRVO, 可选优化,具体来说,以下的写法会优化
std::string GetName() noexcept {
std::string name("UMU618");
return name;
}

避坑

没有必要对返回值再加一次 std::move,因为返回本身就已经是 move,再加一次就是多一次没必要的 move。

现代 C++【2】std::span

前提

多现代?C++ 20。

C++ 17 才有 std::string_view,而相似的 std::span 居然到 C++ 20 才有。

问题

如何解决 C-Style 数组(包含动态分配的连续内存)的退化(array decay)和越界访问(range errors)两大问题?

解决

C 语言解决这两个问题,主要是增加一个长度参数。很多 Win32 API 这样做,例如:

1
2
3
4
5
6
7
8
9
10
11
12
PCSTR WSAAPI inet_ntop(
INT Family,
const VOID *pAddr,
PSTR pStringBuf,
size_t StringBufSize
);

int GetWindowTextA(
HWND hWnd,
LPSTR lpString,
int nMaxCount
);

但它会带来新问题:不小心传错!另外也有一些地方并没有提供长度参数,比如下面 Linux 内核代码里的函数:

1
static inline int ip_decrease_ttl(struct iphdr *iph);

当我们打算把 uint8_t 数组转成 struct iphdr * 时,必须在调用前保证数组长度大于等于最小 IP 头长度。

C++ 的解决方案是:std::span,它是一个连续对象存储的观察者。类似 std::string_viewstd::string 的观察者。它可以同时管理数组的地址和大小,并且它没有数据所有权,仅占用最多两个指针的空间,可以像 std::string_view 一样在绝大多数时候直接按值传递。

例子

以下函数用于获取 IP 头的长度:

1
2
3
4
5
6
std::uint8_t GetHeaderLength(const void* ip_header, size_t size) noexcept;

std::uint8_t ip[] = {0x45, 0x00, 0x00, 0x54, 0xfa, 0xa6, 0x40, 0x00,
0x40, 0x01, 0xb3, 0x9a, 0xc0, 0xa8, 0x0b, 0x02,
0xc0, 0xa8, 0x00, 0x15};
std::cout << "HeaderLength: " << (int)GetHeaderLength(ip, sizeof(ip)) << '\n';

它可以用 std::span 包装成:

1
2
3
4
5
6
template <typename T, size_t N>
inline std::uint8_t GetHeaderLength(std::span<T, N> ip_header) noexcept {
return GetHeaderLength(ip_header.data(), sizeof(T) * ip_header.size());
}

std::cout << "HeaderLength: " << (int)GetHeaderLength(std::span{ip}) << '\n';

另一个便利是,使用 subspan 成员函数可以对其内部指针和长度成对操作,以避免单独处理时可能不小心少处理一个的问题。

避坑

std::spanstd::string_view 一样,没有数据所有权,所以要担心数据失效问题,不要在数据被释放后使用。

下面是个错误示范,来自:std::string_view encourages use-after-free; the Core Guidelines Checker doesn’t complain #1038

1
2
3
4
5
6
7
8
9
#include <iostream>
#include <string>
#include <string_view>

int main() {
std::string s = "Hellooooooooooooooo ";
std::string_view sv = s + "World\n";
std::cout << sv;
}

现代 C++【1】类对象作为函数参数

前提

多现代?C++ 17,因为本文内含 std::string_view

目前 C++ 20 还未普及,CLang 和 GCC 对 C++ 20 不是很上心,【直到今天 2020-08-18】连 std::format 都没有,被 MSVC 甩开。

问题

类对象作为参数究竟应该怎么传?

Effective C++》的条款 20 说:

  1. 宁以 pass-by-reference-to-const 替换 pass-by-value

为什么新规范又建议构造函数 pass-by-value?

原则

  1. 只读访问并且不复制时,使用 pass-by-reference-to-const。

  2. 需要保存对象副本时,并且对象可移动,使用 pass-by-value。

  3. 对象很小时,使用 pass-by-value。

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 只读访问,不需要将 text 保存起来。
void Print(const std::string& text) {
std::cout << text;
}

class Foo {
public:
// 需要保存 message 到类成员变量
Foo(std::string message) : message_(std::move(message)) {}

private:
std::string message_;
};

// std::string_view 很小,连 const 都没必要加,就好像 int 型参数不会加 const
void CallCStyleApi(std::string_view dir) {
if (0 < dir.size()) {
chdir(dir.data());
}
}

说明

Foo 的构造函数使用 pass-by-value,这使得它变成“两用”的,相当于针对这个类对象参数同时实现复制构造函数(ctor)、 移动构造函数(mtor)。

  • 当传一个左值给它时,参数 message 是复制的,但它立刻移动给了成员变量 message_,整个过程发生一次复制和一次移动;

  • 当传一个右值给它时,参数 message 是这个右值移动而来的,然后又立刻移动给了成员变量 message_,整个过程发生两次移动;

1
2
3
std::string name("UMU618");
Foo f1(name); // copy + move
Foo f2(std::move(name)); // move 2 times

如果类实现得妥当,移动两次对象实际上最多可以被编译器优化成零次。

八哥之神【番外篇11】

听说鲁豫要来采访稣
请戴口罩采访

由于没有经费写《后传》就把后传的内容写到《番外篇》了。

  1. 为什么最厉害的是周易?

周易是老钧的化身之一。他看到任何结局,但都不去干预。莫名其妙?没错,这正是他的特征。

圣仙山就会去干预世事演化,而成为天道的执行者之一,本质是个工具人。

大部分英雄电影都有一些角色会因为法律、信仰、道义、情感等原因去干预世事,尤其一些穿越剧,妄想改变历史。这些都是不符合天道的。

天地不仁,以万物为刍狗。所以周易最厉害。

  1. 识界是现实中存在的吗?

当然是。

首先要认识到人类集体显意识是确实存在的,比如中药学就是靠着集体显意识保存下来的。如果某种技能只有一个人会,那么它失传是必然的,这个人一死就失传了。存在集体显意识里就不容易失传,但集体显意识也不一定能够很客观地保存信息,有些人出于某种目的,会篡改信息。并且不是什么信息都可以靠集体显意识保存,比如有些东西无法达成共识。

举个例子,噬菌体,一种可以编程控制的半生命体,可以编程它来定向消灭细菌,比如治疗青春痘……安全有效不含抗生素。它在古代治疗过很多奇怪的疾病,尤其是被下蛊之类的,那时候医学理论不完善,人们便以为是草药起了作用,其实是自然界中的噬菌体治好的。这个事情在集体显意识里是没有记录的,它只在集体潜意识里保存。

PS:1990 年以来,人类几乎没有发现新的抗生素种类了。世界卫生组织 2017 年 9 月份宣布,“确认世界的抗生素频临枯竭”。参考:https://www.who.int/zh/news/item/20-09-2017-the-world-is-running-out-of-antibiotics-who-report-confirms

总之抗生素要完,以后由细菌导致的疾病只能靠噬菌体了。

其次,如果承认个人是有潜意识的,那么集体也应该有集体潜意识。

  1. 稣到底怎么来的?

稣的由来可以有很多解释,但根源来自圣仙山参与写作的《山海经》。

我们注意到现实中的颛顼在八哥宇宙里名字是:姬稣。

作者为什么选择和颛顼攀关系呢?其实颛顼和《八哥之神》的主题十分契合。不信您翻开圣仙山参与写作的《山海经》,里面有一句话特地被重复两次。

有鱼偏枯,名曰鱼妇。颛顼死即复苏。风道北来,天及大水泉,蛇乃化为鱼,是为鱼妇。颛顼死即复苏

古人惜墨如金,为什么这句话非要写两遍?这里面藏着惊天大秘密!——意识是可以重复的,唯一可以穿越时间的,也只有意识。比如现代人死后可以回到古代,但由于记忆无法穿越,所以不会存在任何时间悖论。

“稣”字和“苏”同音,并且就是“鱼”字旁,对应文中多次提到的“鱼”。当圣小开要自称稣时,显然“稣”更合适,因为“苏”是个姓,容易被人误会姓苏。

  1. 《山海经》居然是圣仙山写的?

确切地说,圣仙山以巫咸的身份写了《山海经》的预言部分,而这部分正好因为威力太大,若为坏人得之,天下危矣,故被大禹删除。

也有另一种说法是,巫咸给《山海经》作序用的是大禹看不懂的文字(Bân-lâm-gú),所以到这部分预言内容就慢慢失传了。

幸运的是,识界里还保留着完整的《山海经》,刚好作者就懂 Bân-lâm-gú,所以才能得知这些故事,写出《八哥之神》。不过由于《八哥之神创世手稿》失传,导致并非人人可以通过修炼它而进入识界,天下得以承平日久。

PS:圣仙山和妹妹李灵海,名字合起来就是“山海”,这也是个暗示,历史上的巫阳就是李灵海的前世,秦阳也和巫阳相对应,他们都是同一个意识在不同时期或者境界的具化体。

  1. 《八哥之神》真的是无神论???

是的!姬稣是坚定的无神论,所以有“绝地天通”,破除迷信,不让觋巫扰乱民间。在怪力乱神的时代,姬稣实乃是无神论里少数善终之人,活了 97 岁。

另一个无神论者就很惨,他就是齐凤卿前世帝辛,实则是位明君,但由于是无神论者,得罪势力集团,被污蔑造谣为暴君,至今难以平反。em……不能因为妲己长得漂亮,就说她是狐狸精吧!这太不科学哩!

暂时扯到这里。