一些小知识备忘
-
“回车”是把子车回到行首,“换行”是把子车移动到下一行。所以 Windows 换行符才是
\r\n。 -
cpp。定义 Definition 只能有一个,声明 Declaration 在每个用到的文件里都有一个。这叫 One Definition Rule。
这里很微妙。我们一般说定义 - 实现,但 c++ 里其实是声明 - 定义,“定义”这个词的意思是反的。或者说定义包括了实现。
declaration 是 public interface,definition 是 private implementation。
-
cpp。.h 头文件提供的是声明、模板、蓝图、接口,.cpp 提供的是定义、实现、逻辑。这叫 接口与实现的分离。
-
type qualifier 类型限定符,实际上是类型的“定语”。qualify 有“有资格”和“限定”的意思。
qualify 更多的是“限定”,modify 是“修饰”。
-
AP 是 Assistant Professor。Tenure Track 是“通向终身教职的轨道”,即国内的非升即走。这俩基本上是一个东西。
-
trail 和 track 还不一样。trail 是小路的意思。paper trail 是文件路径,即到最晚的概念的发展历史中所有 paper 的集合。
-
literature 可以指 entire body of published scholarly work on a particular subject。body 指什么东西的全体。
-
ject 是扔的意思。ob 是朝向,引申 object 是客体/对象/拒绝的意思。
-
subject 是向下投掷,所以被引申为权力的主体。
-
project 是向前投掷,引申为投影/投射/共同目标(项目)。
-
tra 是穿过、越过,ory 是场所、事物,所以“投掷穿过的场所” trajectory 就是轨迹。
-
e 和 in 是向外向内,eject 是弹出,inject 是注入。
词源学果然还是没什么意思。就,你告诉我 sub 是下 ject 是投,我想到 下头 都想不到是向下扔引申为上位者,引申为主,引申为主题,引申为课程。
-
-
ifndef MY_HEADER_H / #define MY_HEADER_H / #endif,或pragma once。含义是假如第二次被 include 了那编译的时候会跳过,叫做 Include Guards。 -
cpp,类的继承。
-
子类能否访问父类的成员,是由父类的成员访问说明符 Member Access Specifiers 决定的。public 是对外公开,protected 是自己和子类可访问,private 是自己可访问。
-
子类如何继承父类,是由子类的继承访问说明符 Inheritance Access Specifiers 决定的。public 是 As-a,子类“是一种”父类,原本 public 还是 public,原本 protected 还是 protected,原本的 private 无法访问。private 是说 Is-Implemented-In-Terms-Of,原本的成员都变成 private 仅供内部使用,只是“实现复用”。
-
通过 public 继承和父类的 virtual 虚函数来动态决定方法,即可实现统一接口不同行为,所谓的多态 polymorphism。
-
“C++ 的设计者 Bjarne Stroustrup 认为,默认行为应该是最安全的行为。”因此,为了防止意外的类型转换,c++ 的 class 的继承默认是 private。
还是很深刻的。c++ 原本就是 c with classes。
-
-
cpp 和 go 这样直接管理内存的语言,你按值传结构体就真的把那么大一块内存复制过去了。善用指针。
唉但 cpp 还是太老了。go 很多理念实现起来还是先进啊。
-
const int& 某种方法() const,前面的 const 是对内承诺返回值不被用来修改内部属性,后面的 const 是对外承诺这个方法过程不修改任何内部属性。
-
<< 本质上是二元运算符,它的返回值是左边的那个 ostream 的引用。而它是左结合的,这样就可以实现链式调用了。
-
ClassName(int _a) : a(a) {}。这是构造函数的成员初始化语法。特别地,数组可以用A{a0, a1, a2}。 -
override 说明符,作用于派生类的成员函数,声明它在覆写一个虚函数。这样打错字的话编译器就会报错而不至于像某些语言一样凭空造出一个成员。
-
shared_ptr是共享指针,cpp 的智能指针之一。make_shared<T>(初始化值)是初始化方法,会同时创建 T 对象和控制块。这两条都是 c++11 特性。
-
terminology。body of terms used in technical area, subject of study, profession, etc.。即,一个领域所有术语的集合。“领域”这句话里被展开为技术/研究/职业。
-
syntax 句法。grammar 语法等于 syntax 句法 + morphology 构词法 + phonology 音系学 等。semantics 语义。language = grammar + semantics + pragmatics 语用学。
- pragma 是行动、实践、具体事务的意思。
-
成员函数 = default。比如
ClassName() = default;含义是生成默认构造函数。~ClassName() = default是默认析构函数。还有拷贝构造函数、拷贝赋值运算符(=),移动构造函数和移动构造运算符。 -
virtual 成员函数 = 0,含义是纯虚函数,仅作为接口,本身没有任何实现。
-
内存泄漏和悬挂指针是相对的两个概念,一个是生命周期结束内存没释放,一个是生命周期没结束内存释放了。
-
VS Code 的那个自动补全的小框,可以直接按上下箭头切换显示不同的定义。另外如果它消失了可以按 ctrl + shift + space 把它调出来。
-
Gemini CoT 词汇表,学会了你也是 sota(持续更新):
-
elaborate 精心制作,详细阐述
-
nuance 细微差别
-
assess 评定,估计
-
dissect 分解、剖析。也有解剖的意思。
-
revise 复习;修订。
-
refine 精炼
-
discrepancy 不一致,差异
-
interplay 相互作用
-
pinpoint 针尖;精确定位
-
consolidate 加强,巩固,联合。虽然这个不是 CoT 词汇。
-
reconcile 调和、调解、使一致
-
dispatch 发送,派出。虽然这个不是 CoT 词汇。
-
workaround 通过变通解决问题的方法
-
untangle 整理,理清(复杂问题)
-
outline 轮廓、外形;大纲、概述。可作动词。
-
elusive 难以找到的、难以记起的、困难的。
-
narrative 叙事,陈述
Forming a Narrative -
pedantic 迂腐的、学究的
-
-
class 的 static 成员,实际上是类级别的属性,也就是说,是类属性。它们必须是类内声明类外定义。
-
通过位置传递的参数叫 positional arguments,通过名字传递的叫 named / keyword arguments。只能通过名字传递的叫 keyword-only arguments。例如 python:
def create_user(username, *, is_admin, department):星号后面的是 keyword-only。 -
当一个高频信号由于采样率不足而被错误地解释为一个低频信号时,这个低频信号就被称为高频信号的“化名”,alias。车轮由于帧率不足而看似倒转的马车轮效应就是最经典的 alias。同样,CG 中用有限的像素去采样平滑的斜线导致的锯齿 jaggies 就是原本的斜线的 alias。anti-aliasing,即为“抗锯齿”“抗走样”的意思。
-
虽然很神秘,但是 if 有 although 的意思。C++ has addressed this problem (if imperfectly)。这里 address 是解决的意思。
-
关于 C++ 编译。
-
首先预处理器会处理 # commands。包括 include 的复制粘贴,define 的文本替换。#pragma 是特例,pragma 是 pragmatic information 实践信息(?)的简称,它是专门给(特定种类的)编译器看的。
-
然后编译器开始将 C++ 源码编译为机器码,生成 .o 或 .obj 文件。编译器是逐个 cpp 文件执行的。
-
最后链接器将不同的 object 文件拼到一起。例如一个函数在一个 cpp 中只有声明,在另一个 cpp 里才有定义,那么链接器会把定义链接过来。此外还会链接标准库和运行时启动程序,初始化栈和调用 main 之类的。最终形成可执行文件。
ld 是 gnu 的 linker。所以“ld returned 1”即为“链接器报错”的意思,例如启动程序没能找到它需要的 main。
-
-
关于 inline。
-
inline 最早是针对简短的类函数设计的,是给编译器的性能优化。
-
但是假如多个 cpp 文件包含了同样的库,里面有同样的函数,对链接器来说就会导致违背 ODR。
-
所以 inline 还自带了“ODR 豁免权”的效果,它告诉链接器出现多个该函数是正常的,它们全都相同,保留一个即可。
-
现在编译器都非常聪明,后者的作用重要的多。
-
所以 class 的方法默认是 inline 的。隐式内联。
-
所以 C++ 规定头文件里定义的函数必须 inline。
“定义”是包括具体实现的。在头文件里声明(然后,例如,在同名 .cpp 中定义)的函数就只是暴露了一个接口,那就不需要了。所以可想而知,头文件里定义的函数自然是只有简短逻辑、可以内联的函数。
-
-
关于 diffuse material,漫反射材料。
-
最简单的模型,半球面上均匀随机。
-
Lambertian 散射模型,散射的光强和反射角的余弦成正比。想象一个球心位于法线上、和反射平面相切的球。
-
后者会导致阴影更重、向上的表面更蓝,因为更多的光向法线方向去了。
-
现实中完美的漫反射材料其实很少,所以我们的直觉往往也不那么准,挑看着顺眼的用就好了。
如何随机球面上的向量?你当然可以用球表面积关于任意轴均匀的结论先随 x 再随 theta,但那还要开方不如直接拒绝采样了。
-
-
反射的时候,由于浮点误差,光线出射点有概率出现在物体内部,此时这束光就寄了。这就是为什么
.hit()方法需要一个t_min参数,把非常近的相交排除掉。 -
关于 gamma 值。
-
早期的阴极射线管 CRT 显示器,它们输出的亮度和电压不成正比,具体来说亮度大约等于 电压 ^ 2.2。因为我们指的是 0 到 1 之间,所以它会把亮度压暗。
-
为了兼容这一个世纪以来的所有内容,现代 LCD 和 OLED 显示器也会模拟同样的事情。输出实际亮度约等于输入的亮度值的 2.2 次方,这个 2.2 就被称为 gamma 值。
-
因此,在把图像发给显示器之前,电脑会先执行一次 \(f(x) = x ^ {1/\gamma}\)。这就叫 gamma correction,或者 gamma encoding,把颜色从线性空间映射到 gamma 空间。
-
所以你就知道了,mc 里你调的那个 gamma 就是这个系数的值。把 gamma 调大到 5 左右,画面就会非常亮了。(并不意味着 gamma = 2.2 才是真实亮度。游戏的输出到显示器还有一层 encoding,所以游戏内设 gamma = 1 就是真实亮度。
-
人们之所以把这个设定沿用下来还有一个原因。人的感官是对数的,亮度 250 和 255 之间的差距远远比亮度 10 和 15 的差距小,显示器的 gamma decoding 恰好模拟了这一过程,让计算机内部存储信息更有效率。因此,这一“美丽的意外”就被保留了下来。
这里有一个细节。图片存储时是在 gamma 空间里存的,而运算时必须解码到线性空间。此时毕竟是浮点数形式,数据效率低一点没所谓。然后交给显示器时,就再一次 encode 到 gamma 空间。
-
-
前向声明 forward declaration,就是你 declare 一个类或者函数时,仅仅告诉编译器它们存在,这样可以实现在定义之前声明。
-
其实本身就是我们正常用的,如果两个函数要互相递归,那么应该把后面定义的那个以
T func(T arg);的形式写在前面。或者说就是普通的“声明”这件事。 -
但特殊之处在于它可以解决头文件的循环依赖。如果有一个类只需要另一个类的指针,那么声明一下即可,不用 include 了。
-
这样会导致无法单独使用那个头文件。但既然类用到了那个指针,那设计上来说你就不该单独使用。即,C++ 中你应当把前向声明视为表明“弱依赖”。呃,大概吧,此条存疑。
把这玩意翻译成“前向宣言”听起来很帅。
-
-
datetime 库。
-
包含 date、time、datetime、timedelta 这几个类。
-
datetime 支持 .year、.month、.date 这些东西。timedelta 只有 .day、.second。
-
datetime.now()现在时间。 -
datetime.strptime("2023-01-01", "%Y-%m-%d")。now.strftime("%Y-%m-%d")。 -
timedelta(days=365 * y)。timedelta 支持加减比较啥的。
-
浙公网安备 33010602011771号