当前位置:  开发笔记 > 编程语言 > 正文

C++性能提示和经验法则是谁?

如何解决《C++性能提示和经验法则是谁?》经验,为你挑选了6个好方法。

在编码时,在性能方面要记住什么是一个好的经验法则?有无穷无尽的方法可以针对特定平台和编译器进行优化,但我正在寻找在编译器和平台上同样适用(或几乎)的答案.



1> activout.se..:

脑海中浮现出一句名言:

"我们应该忘记小的效率,比如大约97%的时间:过早的优化是所有邪恶的根源." (Knuth,Donald.结构化编程,参见陈述,ACM期刊计算调查,第6卷,第4期,1974年12月.第268页.)

但也许你不应该按价值传递大数据结构...... :-)

编辑:也许还可以避免使用O(N ^ 2)或更复杂的算法......


我会在任何一天采用O(2)算法.它只需要O(1)的两倍!

2> JaredPar..:

数字#1性能提示是尽早和经常分析您的代码.有很多一般的"不要这样做"的提示,但很难保证这会影响你的应用程序的性能.为什么?每个应用程序都不同.如果你有很多元素但你的程序甚至使用了一个向量(你可能应该......),很容易说按值传递向量是不好的?

分析是了解应用程序性能的唯一方法.我遇到过很多情况,人们"优化"了代码但却没有描述过."优化"最终引入了许多错误,甚至不是代码路径中的热点.浪费每个人的时间.

编辑:

有几个人对我答案的"早期"部分发表了评论.我不认为你应该从第1天开始进行剖析.但是你也不应该等到船上1个月.

我通常首先介绍一下我有一些明确的端到端场景,或者在一个更大的项目中,一个主要功能组件.我需要一两天(通常与QA合作)将一些大型场景聚集在一起并将其抛在代码中.这是一个很好的现场检查,以及早发现明显的性能问题.在这一点上修复它们会容易一些.

在一个典型的项目中,我发现我的代码符合此标准的30%-40%通过项目(100%在客户手中).我很早就把这个时间分类了.


哇,没有早期优化?你们这些人坚果吗?:)我在优化过程中看到的最常见问题之一(我以此为生)是必须处理等待到最后的代码,然后让它快速运行.像重构一样清晰,需要尽早考虑优化以避免......
优化设计(O(n!)与O(log n))或优化代码(在程序集中重新实现某些功能)之间存在很大差异

3> Johannes Sch..:

可能时使用ifswitch代替通过函数指针调用.澄清:void doit(int m) { switch(m) { case 1: f1(); break; case 2: f2(); break; } }而不是void doit(void(*m)()) { m(); }可以内联调用.

如果可能并且没有造成伤害,则更喜欢CRTP到虚拟功能

如果可能,请避免使用C字符串并使用String类.它会经常更快.(恒定时间长度"度量",附加摊销的常数时间,...)

始终通过引用const(T const&)而不是复制值来传递用户定义的类型值(除了它没有意义的地方.例如迭代器).

对于用户定义的类型,总是更喜欢++t而不是t++

const经常使用早期.最重要的是提高可读性.

尽量保持new最低限度.如果可能的话,总是更喜欢自动变量(在堆栈上)

而不是自己填充数组,更喜欢使用空的初始化列表进行初始化,就像T t[N] = { };你想要零一样.

尽可能经常使用构造函数初始化列表,尤其是在初始化用户定义的类型成员时.

使用仿函数(具有operator()重载的类型).它们比通过函数指针调用更好地内联.

不要使用类似的类,std::vector或者std::string如果您的数量固定,则不会增长.使用boost::array或裸阵列并正确使用它.

事实上,我几乎忘了它:

过早优化是万恶之源



4> Konrad Rudol..:

有人提到了函数指针(以及为什么要使用它if).好吧,甚至更好:使用仿函数,它们内联并且通常没有开销.仿函数是一个结构(或类,但通常是前者),它重载运算符(),其实例可以像普通函数一样使用:

template 
struct add {
    operator T ()(T const& a, T const& b) const { return a + b; }
};

int result = add()(1, 2);

这些几乎可以在可以使用普通函数或函数指针的每个上下文中使用.他们通常从任一派生std::unary_functionstd::binary_function但那往往是没有必要(实际上只做过继承了一些有用的typedefS).

编辑上述代码中需要显式类型限定.类型推断仅适用于函数调用,而不适用于实例创建.但是,通常可以通过使用make辅助函数来省略它.这是在STL for pairs中完成的:

template 
pair make_pair(T1 const& first, T2 const& second) {
    return pair(first, second);
}

// Implied types:
pair pif = make_pair(1, 1.0f);

有人在评论中提到,仿函数有时被称为"functionoids".是的杂交 -但并不完全.实际上,"functor"是"函数对象"的缩写(有些奇怪).函数在概念上是相似的,但是通过使用虚函数来实现(尽管它们有时被同义地使用).例如,一个functionoid可能看起来像这样(以及它必要的接口定义):

template 
struct UnaryFunctionoid {
    virtual R invoke(T const& value) const = 0;
};

struct IsEvenFunction : UnaryFunctionoid {
    bool invoke(int const& value) const { return value % 2 == 0; }
};

// call it, somewhat clumsily:
UnaryFunctionoid const& f = IsEvenFunction();
f.invoke(4); // true

当然,由于其虚函数调用,这会失去仿函数所具有的任何性能优势.因此,它在不同的上下文中使用,实际上需要多态(有状态)运行时函数.

C++ FAQ 在这个主题上有更多的话要说.



5> strager..:

在需要之前不要打扰优化.要查明是否需要,请查看个人资料.不要猜; 有证据.

此外,算法优化通常比微算法具有更大的影响.使用A-star而不是暴力寻路会更快,就像Bresenham圈子比使用sin/cos更好.当然也有例外,但它们非常(非常)罕见(<0.1%).如果您有一个好的设计,更改算法只会更改代码中的一个模块.简单.



6> Marcin..:

使用已使用和重复使用的现有已审核代码.(示例:STL,boost vs滚动自己的容器和算法)

由于评论而更新:正确使用已使用和重复使用的现有已审核代码.

推荐阅读
Gbom2402851125
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有