Lazy loaded image
💹104周转行Quant | W02 - C++基础新认知
Words 1971Read Time 5 min
2021-7-2
2026-1-2
type
status
date
slug
summary
tags
category
icon
password
comment
大家好,这里是继续死磕C++的黑犬momo酱。
上周我们聊了“为什么量化的尽头是C++”,很多朋友在后台私信问我推荐C++的学习资料和学习工具 也收获了一些同路人的肯定和支持(十分感谢🙏)。说实话,这一周我复习着《C++ Primer》和网上的教程的笔记,最大的感受不是语法有多难记,而是“恐惧”
以前写Python或Java时,我只关心“功能实现了吗?”;但当你戴上“量化开发(Quant Dev)”的眼镜去重新审视C++最基础的语法时,你会发现:哪怕是一个简单的变量定义,背后都标好了昂贵的“价格”。学完了一周的C++基础,我发现自己以前写的哪里叫代码应该叫CPU的“催命符”,真做交易得落后别人几千年。
本周我们不聊枯燥的if/else、循环抑或是模板类怎么写, 也不粘贴晦涩的代码小片段逐行拆解,这种基础的教程非常了,我们就不需要做重复的事情。我想要做的是,我们站在量化的角度,来聊聊隐藏在基础语法背后的“量化三观”和我的一些新认知,希望也能帮各位读者对QD日常工作有一些直观的印象。
💡如果有一些C++或者量化术语你不熟悉,没关系,重点是体会在发生什么,相关的知识我以后会有更细致的分享。

1. 变量“住”哪?(Stack vs Heap)

如果是做Web和前端开发,你可能不太在乎变量存在哪;但在高频交易里,住错了地方就是“事故”。
初学C++最容易滥用的是 new 关键字,或者malloc很多自己没有办法管理的内存。
想象这样一个场景,比如来了一个行情Tick,习惯性写一句 Order* o = new Order();。
在普通软件里这没问题,但在量化系统的热路径(Hot Path, 简单理解为从接收到行情到策略计算结束发出报单的代码执行路径)上,这是大忌。
  • 堆(Heap)的代价new 需要操作系统在杂乱的内存堆里帮你找空地,这不仅慢,而且时间不可控(可能这次1微秒,下次100微秒)。这种“抖动”对于追求微秒级响应的策略是致命的。
  • 栈(Stack)的优势:栈上的内存分配几乎是零成本的(指针移动一下而已)。
我的新认知:
在量化里,能用栈(局部变量)就绝不用堆。如果必须用动态内存,必须预先分配好内存池(Memory Pool),池化组件是一个好东西,当你没有性能优化方案的灵感时,先想想pool。

2. 浮点数的“谎言”

我们来聊聊钱。
如果你在很多编程语言里计算 0.1 + 0.2,结果往往不是 0.3,而是一个无限接近的小数。
基础语法告诉我们有 float 和 double。
但实战经验会告诉你:别信它们。
  • 精度陷阱:在金融里,一分钱的对账误差都可能导致系统熔断。double 的底层二进制表示注定会有精度损失。
  • 行业惯例:为什么很多交易所推过来的数据(FIX/二进制流)里,价格是整型(int64)?
    • 比如茅台价格 1500.23,传输过来往往是 15002300(单位是微元)。
我的新认知:
尽量使用定点数(Fixed Point)思维。用 int64_t 来存价格,算完了再除回去。

3. NO COPY,只传References

C++最迷人也最基础的特性之一:引用(Reference &)。
假设你有一个包含全市场5000只股票快照的大对象 MarketSnapshot。
你需要写一个函数检查风控:void CheckRisk(MarketSnapshot snap)。
  • 萌新写法(值传递):不加 &。C++会尽职尽责地把这5000只股票的数据完整拷贝一份给函数。CPU 疯了,内存爆了,延迟炸了。
  • 量化写法(引用传递)void CheckRisk(const MarketSnapshot& snap)。加了 const &,相当于只给函数一个“眼神”或者“遥控器”,零拷贝,直接操作原数据,且保证不被修改。
我的新认知:
C++程序员需要培养一种强迫症,看到复杂对象传参不带 &,就像看到钱掉在地上一样难受。

4. Vector是朋友,Map是杀手

C++教科书说查找要用 std::map (红黑树),因为它是 O(logN);std::vector 是 O(N),太慢。
但在HFT场景下(比如处理Level 2行情的十档买卖盘),这个结论往往是错的
  • 缓存友好性(Cache Locality)
    • Vector 的数据在内存里是排排坐的,CPU读取时可以一次性预取(Prefetch)很多,极快。
    • Map 的节点散落在内存各处,CPU读它需要跳来跳去,Cache Miss(缓存未命中)极其严重。
我的新认知:
在数据量不大(几十上百个元素)时,遍历一个 vector 往往比在 map 里查找要快得多。

5. 异常处理 (Exception):热路径上的“禁区”

C++教科书说遇到错误用 try...catch,优雅又安全。
但是在量化实战的Tick-to-Trade(行情触发交易)场景下,严禁抛出异常。
实际上C++的异常机制(Stack Unwinding)非常昂贵。一旦抛出异常,CPU需要花费大量周期去回溯堆栈,这对于微秒级的策略是毁灭性的。此外,异常的存在会阻碍编译器进行某些激进的优化。
真实的实盘交易的代码,总是在用if和return。
我的新认知:
在量化里,Performance > Elegance,速度永远第一顺位。

当然,C++语法基础还有很多部分譬如指针、模板类、CRTP、惯用法等等很多细碎的话题,限于篇幅我们不可能把所有和量化相关的细节都盘一遍。
重要的是,这一周的学习让我明白,所谓的“量化开发门槛”,并不在于你能背多少个C++关键字,而在于你是否具备“**硬件思维”,关键是需要对自己每写的一行代码的准确性和性能负责,作为QD,我们的使命就是让程序跑的又快又准,而不是仅仅实现一个可用功能外加代码优雅而已(至少我感觉量化工作中并不追求代码要优雅,工程落地能力>代码规范)。
📂 学习资源与代码归档:
下周预告:W03 - C++的OOP魔法(基础)
👋下周五见,我是还在死磕指针和红黑树的黑犬momo酱。
🙋提问:各位开发者在写代码的时候,什么时候考虑性能最优化?还是并不care?
上一篇
104周转行Quant | W01 - 量化的尽头是C++?
下一篇
104周转行Quant | W03 - C++的OOP魔法(上)

Comments
Loading...