16

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

什么东西可以使 C++ 比 C 慢?

面试官问的很深,每次我说什么的时候总是问“还有别的吗?”。

我的想法:

C 中不可用的 C++ 功能可能需要一些成本。

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

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

有更好的主意吗?

任何帮助将不胜感激。

谢谢 !!!

4

7 回答 7

27

C++ 与 C 相比没有什么本质上慢,但是,惯用的 C++ 代码往往比执行相同任务的惯用 C 代码慢得多,也更重。惯用语是这里的关键;如果您编写 C 代码来执行任务的方式与在 C++ 中执行该任务的方式完全相同,那么它会同样慢。另一方面,如果您知道隐藏成本在 C++ 中通常在哪里蔓延,您可以努力将其保持在最低限度,并在不增加成本的情况下获得 C++ 的好处。

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

另一个大领域是字符串处理。在惯用的 C 语言中,弦乐是一举用snprintf或类似的方式构建的。在 C++ 和许多其他具有更强大的字符串类/类型的语言中,字符串的连接(逐段构造)是惯用的。这是非常低效的,导致多个分配/解除分配步骤、副本等,更不用说由此产生的内存碎片。我不确定 C++ 的最佳实践会涉及哪些(我不精通 C++),但应该有办法将这种影响降到最低。

当然,最普遍的是隐藏代码。这是一个包罗万象的东西。在 C++ 中编写代码很容易,许多你从未见过的额外代码被执行。构造函数/析构函数、重载的运算符和模板是最明显的原因。同样,如果您想在 C 中以相同的方式做事,成本将是相同的,但不同之处在于,在 C 中,您会立即看到成本,因为您必须自己编写它。

于 2012-05-27T18:26:47.470 回答
14

没有。事实上,C++ 比 C 更快。曾经std::sortqsort?

人们说虚函数需要时间来调用。他们是这样。但是 C 中的等效于在 vtable 中查找也是如此。如果你用两种语言编写等效的逻辑,C++ 版本将更易于维护、更简洁和更快。

编辑:哦,是的,如果需要,您可以printf从 C++ 调用,或者如果需要,可以完全重新执行流实现。

我有没有提到由于放错 NULL 终止符而崩溃的程序的性能是相当无关紧要的?

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

于 2012-05-27T15:27:52.893 回答
7

哇...答案中对 C++ 的热爱,所以我会咆哮一下作为魔鬼的拥护者。

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

C++在更大程度上依赖编译器来“解释”意图,通过多次迭代爬过模板、类、宏等的许多层。通过翻译的每个循环都有可能遇到意外后果的规律。据我所知,处理器没有本地处理 C++ 结构的寄存器或操作码,因此每个都必须分解为简化的部分。在这方面,编译器和代码标准是王道。在某些情况下,这在哲学上相当于拥有数学博士学位的老师(编译器)教三年级学生(处理器)。

我喜欢 C++ 并保守地使用它,但多年来我很少看到它写得很好。我想强迫一些人查看最终由构建反刍的程序集或机器代码,直到他们了解它是多么复杂。糟糕的 C 是一回事,糟糕的 C++ 可能会成倍恶化。

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

于 2012-05-27T21:04:21.377 回答
5

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

这意味着要在 C 中编写一个正确的程序以试图避免存在 C++ 功能的问题,您将必须执行与 C++ 在幕后执行的类似操作。这导致两种情况下的性能相似。

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

于 2012-05-27T15:30:10.317 回答
5

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

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

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

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

于 2012-05-27T15:44:58.533 回答
4

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

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

于 2012-05-27T15:31:28.277 回答
2

先验不是性能问题,但 LLVM 代码库既不使用 RTTI 也不使用异常,因为它们在代码大小方面被认为成本太高

于 2012-05-27T18:05:50.697 回答