有人能指点我一篇文章,或者在这里写一些关于一些C++编程习惯的技巧,这些习惯通常是有效的(没有真正的缺点)并且可以提高性能吗?我不是指编程模式和算法的复杂性 - 我需要一些小的东西,比如你如何定义你的函数,要做的事情/要避免在循环中,在堆栈上分配什么,堆上的内容等等.
这不是关于如何更快地制作一个特定的软件,也不是关于如何创建一个干净的软件设计,而是关于编程习惯 - 如果你总是应用它们,你将使你的代码比速度稍慢一点.
Lau*_*ves 33
有效的C++,更有效的C++,有效的STL和C++编码标准中的许多技巧都在这一行.
这样一个提示的一个简单例子:尽可能使用preincrement(++ i)而不是postincrement(i ++).这对于迭代器尤为重要,因为后增量涉及复制迭代器.你的优化器可能能够解除这个,但是编写preincrement并不是额外的工作,那么为什么要冒这个风险呢?
Mic*_*fik 26
如果我理解正确的话,那就是要求避免过早的悲观化,这是避免过早优化的一个很好的补充.根据我的经验,要避免的首要任务是尽可能不复制大型对象.这包括:
最后一个子弹需要一些解释.我不能告诉你我见过多少次:
class Foo
{
const BigObject & bar();
};
// ... somewhere in code ...
BigObject obj = foo.bar(); // OOPS! This creates a copy!
Run Code Online (Sandbox Code Playgroud)
正确的方法是:
const BigOject &obj = foo.bar(); // does not create a copy
Run Code Online (Sandbox Code Playgroud)
这些指南适用于大于智能指针或内置类型的任何内容.此外,我强烈建议花时间学习分析您的代码.一个好的分析工具将有助于捕获浪费的操作.
小智 16
A few of my pet peeves:
if (a && b),如果b更可能是假的,则首先将其放置以保存a的评估.还有许多其他"坏习惯",我不会提及,因为在实践中,现代编译器/优化器将消除不良影响(例如,返回值优化与传递引用,循环展开等).
Tom*_*sen 12
Agner Fog的" 在C++中优化软件 " 通常是优化技术的最佳参考之一,既简单又明显,也更先进.另一个很大的优点是可以在他的网站上免费阅读.(请参阅他的网站名称中的链接,以及pdf的纸质标题链接).
编辑:还要记住,90%(或更多)的时间花费在代码的10%(或更少)上.因此,一般来说优化代码实际上是针对您的瓶颈.进一步就知道,现代的编译器会做optimzation比大多数程序员要好得多,特别是微优化,如延缓变量初始化等编译器往往在优化非常好,所以花时间写稳定,可靠是重要和有益的和简单的代码.
我认为,至少在大多数情况下,更多地关注算法的选择而不是微优化是值得的.
小智 11
使用仿函数(已operator()实现的类)而不是函数指针.编译器可以更轻松地内联前者.这就是为什么C++ std::sort比C更倾向于表现得更好(当给出一个仿函数时)qsort.
从你的问题看来,你已经知道"过早优化是邪恶的"哲学,所以我不会那么鼓吹.:)
现代编译器已经非常聪明地为您进行微优化.如果你太努力,你通常可以比原始的直接代码慢.
对于小的"优化",您可以安全地进行操作,而不会影响代码的可读性/可维护性,请查看Sutter和Alexandrescu的C++ Coding Standards一书中的"过早的悲观化"部分.
有关更多优化技术,请查看Bulka&Mayhew的Efficient C++.仅在通过剖析合理时使用!
有关良好的通用C++编程实践,请查看:
在我的头脑中,一个很好的一般性能练习是通过引用传递重量级对象,而不是通过复制.例如:
// Not a good idea, a whole other temporary copy of the (potentially big) vector will be created.
int sum(std::vector<int> v)
{
// sum all values of v
return sum;
}
// Better, vector is passed by constant reference
int sum(const std::vector<int>& v)
{
// v is immutable ("read-only") in this context
// sum all values of v.
return sum;
}
Run Code Online (Sandbox Code Playgroud)
对于像复数或二维(x,y)点这样的小对象,对于通过复制传递的对象,该函数可能会运行得更快.
对于固定大小的中等重量对象,如果函数通过副本或对象的引用运行得更快,则不太清楚.只有剖析才能说明问题.我通常只是通过const引用传递(如果函数不需要本地副本),只有在分析告诉我时才会担心它.
有些人会说你可以不假思索地内联小类方法.这可能会提高运行时性能,但如果有大量内联,它也可能会延长编译时间.如果类方法是库API的一部分,那么最好不要内联它,无论它有多小.这是因为内联函数的实现必须对其他模块/类可见.如果您在内联函数/方法中更改了某些内容,则需要重新编译引用它的其他模块.
当我第一次开始编程时,我会尝试微观优化一切(那是我的电气工程师).真是浪费时间!
如果您使用的是嵌入式系统,那么事情会发生变化,您无法将记忆视为理所当然.但这是另一整套蠕虫.
除非您真的确定另一种容器类型更好,否则请使用“std::vector”。即使“std::deque”、“std::list”、“std::map”等看起来更方便,向量在内存使用和元素访问\迭代次数方面都优于它们。
此外,更喜欢使用容器成员算法(即'map.equal_range(...)')而不是其全局对应算法('std::equal_range(begin(), end()...)')
我喜欢这个问题,因为它要求一些"好习惯".我发现编程中可取的某些东西最初是一件苦差事,但一旦成为习惯就变得可以接受甚至变得容易.
一个示例始终使用智能指针而不是原始指针来控制堆内存生存期.当然,另一个相关的问题是养成了一直使用RAII进行资源获取和发布的习惯.另一个是始终使用异常进行错误处理.这三种方法倾向于简化代码,从而使代码更小,更快,更容易理解.
你也可以隐式内联getter和setter; 总是充分利用构造函数中的初始化列表; 并始终使用std库中提供的find和其他相关函数,而不是制作自己的循环.
不是特别是C++,但通常值得避免数据复制.在具有大量内存分配的长时间运行的程序中,将内存分配视为设计的主要部分是值得的,因此您使用的内存来自可重用的池,尽管这不一定是常见的事情.被认为值得养成习惯.
还有一件事 - 如果您需要功能,请不要将代码从一个地方复制到另一个地方 - 使用一个功能.这样可以减小代码大小,并且可以更轻松地优化使用此功能的所有位置.
vector,如果你要继续添加数据为未知大小的数据.如果要重复呼叫push_back(),请使用reserve()或deque改用.list则可能是正确的选择.deque则可能是正确的选择.list可能是错误的选择.list但是您从不在列表中向后移动,那么您可以forward_list根据自己的喜好找到更多内容.它不会更快,但会占用更少的空间.请注意,此建议变得更适用于容器越大.对于较小的容器,vector可能总是正确的选择,因为较低的常数因素.如有疑问,请以基准为准.
unordered_foo/ hash_foo,则没有多少选择.使用四个容器中的任何一个都适合您的需要.unordered_foo,请使用它而不是有序版本,如果您不关心元素的顺序,并且您对该类型有良好的散列函数.dynamic_castdynamic_cast有时是做某事的唯一选择,但通常dynamic_cast可以通过改进设计来消除使用.dynamic_cast为a typeid后面的static_cast任何一个.