什么事情(或在什么情况下)可以使C ++比C慢?

时间:2012-05-27 15:24:51

标签: c++ c exception polymorphism virtual

这是一个面试问题,面试已经完成。

什么能使C ++比C慢?

面试官问得很深,每当我说些什么时总是问“别的什么?”

我的想法:

C中没有的C ++功能可能会有一些成本。

例如,如果我们使用赋值在构造函数内初始化类的成员而不是初始化列表,则可以在构造函数的主体之前调用成员的默认构造函数,然后通过赋值将该值清除。

需要通过搜索虚函数指针来调用虚函数。这是一个开销。

有更好的想法吗?

任何帮助将不胜感激。

谢谢!!!

7 个答案:

答案 0 :(得分:24)

对于C ++而言,没有什么本身更慢,但是,惯用的C ++代码往往比执行相同任务的惯用C代码慢得多,也更重。惯用这个词在这里是关键;如果您编写C代码来执行任务的方式与在C ++中执行该任务的方式完全相同,那么它将同样缓慢。另一方面,如果您知道隐藏成本通常会在C ++中出现的地方,那么您可以尽量保持最低限度,并在没有多少成本的情况下获得C ++的好处。

首先是动态内存分配。在C中,您可以看到您执行的所有动态内存分配,因为它都是显式的(以对malloc的调用形式或对返回已分配对象的第三方库函数的调用)。在C ++中,由于隐藏的分配在其构造函数中发生,因此对象的存储持续时间是自动的许多类对象仍然会产生动态内存分配。一个好的C ++ STL(或第三方库)实现可以通过在对象本身中包含小缓冲区来避免大量此类成本,并且仅在需要大缓冲区时执行动态分配,但实际上很少这样做。 (如果我没有弄错,llvm的libc ++会这样做,但是GCC的libstdc ++没有。)因为这是一个通常不在你自己的代码控制范围内的实现质量问题,你可以做的最大限度地减少影响的是意识到自动对象分配动态内存的可能性,并避免创建超出您需要的内容(例如,尽可能使用指针或引用)。这对您的代码也有其他好处。

另一个重要领域是字符串处理。在惯用语C中,字符串是用snprintf或类似的一次构造的。在C ++和许多其他具有更强大的字符串类/类型的语言中,字符串的连接(逐个构造)是惯用的。这是非常低效的,导致多个分配/解除分配步骤,副本等,更不用说产生的内存碎片。我不确定C ++的最佳实践会涉及什么(我不精通C ++),但应该有办法尽量减少这种影响。

当然,最常见的是隐藏代码。这是一种全能的方式。在C ++中很容易编写代码,从而可以执行许多您从未看到过的额外代码。构造函数/析构函数,重载运算符和模板是最明显的原因。同样,如果你想在C中以相同的方式做事,成本将是相同的,但不同的是,在C中,你立即看到成本,因为你必须自己写。

答案 1 :(得分:12)

无。事实上,C ++比C更快。曾经std::sortqsort进行比较?

人们说虚拟功能需要花费时间来调用。他们是这样。但是相当于在vtable中查找的C也是如此。如果您使用两种语言编写等效逻辑,则C ++版本将更易于维护,更清晰,更快速。

编辑:噢,如果你愿意,可以从C ++中调用printf,或者如果你愿意,可以完全重新执行流实现。

我是否提到由于错误的NULL终止符导致崩溃的程序的性能相当不重要?

宏和内联函数将“膨胀”C可执行文件,就像模板在C ++中一样。

答案 2 :(得分:6)

哇...在答案中对C ++的热爱很多,所以我会像Devil's Advocate一样咆哮。

在原子语言规模上,我同意在C ++中很少或根本没有显着“慢”执行。在更高的层面,它变得复杂。 C ++是一个有用的工具,但通常是panache不恰当地作为所有问题的解决方案。当我们使用最简单的语言来描述问题时,它会更好,有时候这是C ++的其他时间......汇编,操作码,解释语言。

C ++在很大程度上依赖于编译器来“解释”意图,通过多次迭代爬行遍历多层模板,类,宏等等。翻译中的每个循环都有可能遇到law of unintended consequences。据我所知,处理器没有本机处理C ++构造的寄存器或操作码,因此每个都必须分解为简化部分。在这方面,编译器和代码标准是王道。在某些情况下,它是教授三年级学生(处理器)的数学(编译器)PHD教师的哲学等价物。

我喜欢C ++并保守地使用它,但多年来我几乎没有看到它写得很好。我想强迫一些人看一下最终由构建反刍的程序集或机器代码,直到他们理解它是多么复杂。坏C是一回事,糟糕的C ++可能会呈指数级恶化。

面试的更好答案......“你的团队什么时候才会认为C ++不是问题的答案?”

答案 3 :(得分:5)

C ++中的大多数功能都是解决C中(潜在)问题的解决方案(例如:构造函数,以确保创建的数据包的有效性(C中的struct

这意味着要在C中编写一个试图避免出现C ++特性问题的正确程序,您将不得不执行C ++在幕后执行的类似操作。这导致两种情况都有相似的表现。

当然,您总是可以编写“更快”的草率程序,但在所有情况下都无法正常工作

答案 4 :(得分:5)

C有restrict,C ++没有,尽管大多数编译器都将它作为扩展。

还有C ++没有的可变长度数组。

答案 5 :(得分:5)

  

有更好的想法吗?任何帮助将不胜感激。

C ++中的STL很少比C中的特殊编码等效项慢。但是,STL的便利偶尔会导致编写较慢的代码。例如,假设一组固定的100个项目,其中的变量选择为10或15。假设程序的时间关键循环多次询问是否已选择项i。支持这种时间关键循环的快速数据结构将是100个bool的阵列(或矢量等)。但是,填充std::set<size_t>可能更容易在C ++中编码而不是填充数组。出于这个原因,C ++程序员可能更喜欢数组上的集合。

当然,较慢的代码是否有问题取决于时间关键循环将看到多少服务。如果对阵列技术进行编程需要额外的半小时,并且在程序的整个生命周期内节省的总执行时间为0.5秒,则设置技术可能更可取。另一方面,如果总执行时间节省是30天,那么阵列技术可能更可取。

可能会给出许多类似的答案。祝你的面试顺利。

答案 6 :(得分:2)

先验不是性能问题,但LLVM代码库既不使用RTTI也不使用例外,因为它们被视为too costly in terms of code size