跨框架 AI 引擎的零拷贝实践:用 std::span 与 DLPack 实现 Tensor 零延迟流转
一、零拷贝的代价幻觉
你大概率写过这样的代码:拿到一个std::vector<float>,想传给另一个函数处理,又不想拷贝,于是你用了 C++20 的std::span<float>。写完之后感觉良好,觉得自己用上了"现代C++的安全数组视图"。
但你有没有想过一件事:span[i]越界访问时会发生什么?
答案不是抛异常,不是 assert 失败,而是,未定义行为,和裸指针越界一模一样。
这不是实现上的疏忽。打开 P0122 提案的修订历史你会发现,这份提案从 2015 年提交到 2018 年最终进入 C++20 标准,前后经历了 7 次修订(R0 到 R7),而几乎每一轮审议中都有人提出"operator[] 是否应该默认做边界检查"这个问题。标准委员会的最终裁决是:不做。越界就是 UB。想要安全?等 C++26 的.at()方法,或者自己开编译器的 hardening 模式。
这个决策让很多从gsl::span迁移过来的开发者困惑,毕竟gsl::span的operator[]是强制做边界检查的,越界直接 terminate。两个名字几乎一模一样的类型,在安全性上的哲学却截然相反。
我的判断是:标准委员会的这个决策是对的,但对的原因并不是多数人以为的"一次比较指令的开销可以忽略"。真正的代价在于,一旦operator[]内部包含分支(哪怕是一个必定
