DeepSeek生成的代码真的好吗? - (1)
这个标题起的有点儿用我们东北话就是“欠欠儿”的,主要还是为了吸引一些点击。因为好久没有正经写文章,推荐系统估计已经把我忘了,今天我们就用DeepSeek写一段代码来看看,TA写的究竟怎么样?
我们构造一个这样的问题:
如何改进C++ std::vector,使其使用栈上内存而非堆上内存?
坦诚的说这个问题是有一定难度的,至少C++初学者不会碰到(甚至不会思考)这个问题。同时这也不是一个无痛呻吟、照本宣科的问题,在实际应用中这很重要:vector作为STL最常用的数据结构之一,它有一个很大的问题是它的内存每次都要在堆上申请和释放,如果我们的算法里只需要一个较小的线性存储空间,每次都从堆上操作是非常浪费时间的,对于一些性能要求高的场景来说是很不友好的,而如果我们从栈上申请内存成本几乎是0。
当然有一种解法是完全自定义一个类,抛弃std::vector —— 可以这样做但并不好,因为有大量的模板方法需要依赖std::vector的接口。
首先我们看看DeepSeek给出的结果:
DeepSeek给出的答案比较长,我截图了一下大家可以点开自己看看,第一眼看上去确实很惊艳!写的真好(比我想象的好很多!)。
考虑到我们上面提到的尽量兼容vector接口的需求,使用std::array / alloca函数 / StackVector这三个方法都不可行(这几个方法还有其他问题这里就不说了),其中第二个方法自定义allocator是比较理想的方案。
这个方案粗看上去没什么问题,照搬这个代码应该是可以运行的(我还没测试过),但是如果你要细看,你会发现这里面有很大的坑,真的这么用了性能反而变得更差了。
我们下面就说说有什么坑,由于这不是一篇关于C++进阶的教程所以细节就不解释了:
- Allocator对象是会在STL容器内复制的,因此数据不应该实际存储在Allocator对象内,也就是T buffer[N];这一行的问题,这会导致其存储的对象会被反复的复制。
- Allocator的实现方法实际上在申请栈上的内存的同时,也初始化了对象:同样是上面这行代码的问题,这会导致vector在实际处理任何对象之前,就已经实例化了N个对象,这对于构造函数较为复杂的类型类说是一个灾难。
上面这两个问题怎么改?第一个很容易,Allocator保存一个实际占用栈上内存的对象的指针即可;第二个有些麻烦,逻辑上我们应当在栈上申请sizeof(T) * N的空间,但是这里要注意,C++的对象是有内存布局优化的,并且编译器一定不会紧凑布局这些对象,这么做就会造成运行时的内存错误。正确的做法是使用__alignof__(不同编译器不完全一样,msvc好像是__alignof)来获得类型T的内存布局方法,然后构造不同的内存结构,所以实际上实现要比这个复杂很多。
结论怎么说呢,我们肯定不能用这一个Case就肯定或者否定DeepSeek代码的生成能力,而且作为一个通用的模型来说,我觉得这已经非常的牛了(我估计超过了99%的C++程序员了……),要做到更好,把C++吃透可能需要给TA更多的优质代码吧。
以上感谢阅读,欢迎评论区讨论,喜欢就关注、点赞吧~