摘要:C++带来了丰富的语言特性,class给你直观的面向对象思维能力,lambda给你函数式编程的自由,auto帮你甩掉重复写出类型的包袱,模板帮你少些很多代码。这些都是爽点。恶心的地方,也不少,但原因只有一个,只重视追加特性,不重视约束特性。
实在忍不住了,好想喷C++,是第一次喷它,也是最后一次喷它,以后就老死不相往来吧。
C++带来了丰富的语言特性,class给你直观的面向对象思维能力,lambda给你函数式编程的自由,auto帮你甩掉重复写出类型的包袱,模板帮你少些很多代码。这些都是爽点。恶心的地方,也不少,但原因只有一个,只重视追加特性,不重视约束特性。
构造函数就是一个典型的例子。默认情况下,它会自动帮你生成拷贝构造函数、移动构造函数、默认构造函数。这一点就足够离谱。为什么不是按需提供?默认提供这些东西,就是背着开发者搞事情!构造函数,还能重载多次,还有不同写法上的花样,这就导致class在初始化的时候,有太多写法:
// 假设A是一个classA a;A a(1);A a = 1;A a{};A a = {1};A a = {1,2,3};A a{1,2,3};A a(1,2,3);直接眼晕!这种代码,看着就遭罪!构造函数,按照入参的个数和类型,来揣摩它调用之后的效果,变态!
你就不得不搞出一套所谓的编程规范,然后写一些工厂函数,用通俗易懂的函数命名把这些重载的构造函数区分开,降低初始化一个class的心智负担。
搞笑的是,有人说这不是语言问题,而是编程规范问题。如果你语言层面把这个问题处理好了,还用得着搞什么狗屁规范?看见了么,光引入构造函数和函数重载,却不约束这些特性,结果就是乱成一片。
糟糕的还在后头,拷贝构造函数,移动构造函数,左值,右值,左值引用,右值引用。引入这么多概念,如果可以把问题解决好,无可厚非,可真的解决了么?看看这个例子:
class A {public:A {std::cout禁用构造函数优化,编译这个程序,你会发现编译成功,一旦执行,你就瞎眼:
default constructordestructive constructorcopy constructordestructive constructor合着先析构了,再拷贝?都析构了,还拷贝个锤子!你单独去看吧,都合乎它的概念体系,一点语法问题都没有,可它就是个错误,一点存在的意义都没有。
气愤的是,C++不在语言层面解决这种问题。那怎么解决呢?无非是定规范,让人遵守规范编程。要么是前人踩坑,总结一堆避坑指南,写成书、博客,后边的程序员奉为圣经,牢记背熟。
这。。。有意思么?合着C++程序员的价值就在于把这种东西像公式一样背的滚瓜烂熟,就在于避开语言的坑?我想肯定不是。
我不认为这是C++语言设计的过人之处,它就是懒,不走心,不反思,不约束,只顾一头莽下去,追加特性。
C++的模板、concept也好不到哪里去。亮点无非就是,有了模板,可以使用泛型,减少代码量,不用为一个个具体类型编写代码。有了concept,可以搞编译期的类型系统推导,收窄类型,能利用这种类型系统,在编译的时候提早发现问题,比如下面的代码(来自ladybird项目):
templateinline constexpr bool IsSame = false;templateinline constexpr bool IsSameinline constexpr bool IsLvalueReference = false; templateinline constexpr bool IsLvalueReferenceauto declvalue -> T; template...); };可你一想,如果为了减少代码书写量,把模板的逻辑写得复杂,代码理解起来会非常难,非常不清晰,出问题了就特别不好排查。
你是编写的代码少了,可是编译器生成的代码丝毫不少,不亚于你手动给每个类型一一编写代码。代码最重要的是健康运行,好维护,模板太复杂无疑就是一种破坏。
concept这一套东西,和typescript的类型体操非常像。typescript有类型系统和类型推导,是因为javascript是动态语言,动态的类型会导致程序出现问题,比如 access value of null or undefined,加入类型系统,就可以追踪类型,约束类型,避免一个类型随意变成另一个类型,进而减少运行时的问题。
C++引入concept,就是为了收窄类型。比如一个函数为了性能考虑,只想让入参能够移动,而不能拷贝,照以前的做法,就必须用class继承,现在不用了,有了concept,就能把这种类型描述出来。
可你再一想,类型为什么要约束一下?就是因为像拷贝、移动这些特性,设计得太散、太自由,特性之间缺乏关联。模板里typename声明的类型没有约束,编译器无法拦截错误,比如这个:
template原本这种约束、关联,就该是C++语言设计的时候要考虑到的,并落实到编译器上,可现在是提供一套机制,让程序员自己搞定,倒是把编译器的工作甩给了程序员!C++就是在偷懒。形象来说,后出来的特性总是在填之前特性留下的坑,而后出来的特性自身又会挖坑。
C++较C引入那么多特性,结果埋了很多坑,语言体系的扩大并没有换来程序的健壮。开发者必须付出大量的时间和心力,克服这些坑,才能回本儿,尝到C++的好处。
C++能够骄傲的,也让它活下来的底气,就是出生得早,有那么几代人找不到其它趁手的工具,只能用它,却建造出现代软件体系的基石。用C++的人真的是喜欢C++么,不不不不,他们只是用惯了,也不愿折腾了,更离不开C++的生态(那些库啊,工具啊,软件啊,引擎啊等等)。
最后,祝福C++能活一天就多活一天,今后不再相见。
来源:有趣的科技君