我的问题是出于好奇,而不是是否有其他方法可以解决这个问题。这是一个奇怪/有趣的问题,所以请以开放的心态阅读它。
让我们假设有一个游戏循环每帧都被调用。游戏循环依次通过无数的 if 语句调用多个函数。例如,如果用户将 GUI 设置为 false,则不要刷新 GUI,否则调用 RefreshGui()。循环中还有许多其他 if 语句,如果它们为真,它们将调用各自的函数。有些是 if/if-else.../else,在最坏的情况下成本更高。即使被调用的函数,如果 if 语句为真,也有逻辑。如果用户想要对所有对象进行光线拾取调用 FunctionA(),如果用户想要对灯光进行光线拾取,则调用 FunctionB(), ...,否则调用所有函数。希望你明白了。
我的意思是,那是很多多余的 if 语句。所以我决定改用函数指针。现在我的假设是函数指针总是比 if 语句快。它是 if/else 的替代品。因此,如果用户想要在两种不同的相机模式之间切换,他/她可以按 C 键在它们之间切换。键盘的回调函数将函数指针更改为正确的 UpdateCamera 函数(在这种情况下,函数指针可以指向 UpdateCameraFps() 或 UpdateCameraArcBall( ) )...你明白了它的要点。
现在回到问题本身。如果我有几个更新函数都具有相同的签名(假设为 void (*Update)(float time) ),那么函数指针可能会指向其中的任何一个。然后,我有一个用于存储指针的 vector 。然后在我的主更新循环中,我遍历 vector 并调用每个更新函数。我可以删除/添加甚至更改更新的顺序,而无需更改底层代码。在最好的情况下,我可能只调用一个更新函数,或者在最坏的情况下调用所有更新函数,所有这些都带有一个非常干净的 while 循环并且没有讨厌的(可能嵌套的)if 语句。我已经实现了这部分并且效果很好。我知道,对于负责遍历 vector 的 while 循环的每次迭代,我都在检查 itrBegin == itrEnd。更具体地说,while (itrBegin != itrEnd)。有什么办法可以避免调用 if 语句吗?我可以使用分支预测来发挥我的优势吗(或者我是否已经在不知不觉中利用了它)?
再次强调,请按原样回答这个问题,即我不是在寻找不同的方法(尽管我们非常欢迎您提供一种方法)。
EDIT: A few replies state that this is an unneeded premature optimization and I should not be focusing on it and that the if-statement(s) cost is minuscule compared to the work done in all the separate update functions. Very true, and I completely agree, but that was not the point of the question and I apologize if I did not make the question clearer. I did learn quite a few new things with all the replies though!
最佳答案
there is a game loop that is being called every frame
这是一种倒退的描述方式。游戏循环不在帧期间运行,帧在游戏循环的主体中处理。
my assumption is that a function pointer is always going to be faster than an if statement
你测试过吗?这不太可能是真的,尤其是当您频繁更改指针时(这确实会扰乱 CPU 的分支预测)。
Can I use branch prediction to my advantage (or am I taking advantage of it already without knowing)?
这只是一厢情愿。通过在循环中进行一个间接调用来调用一堆不同的函数,您肯定会违反 CPU 分支预测逻辑。
More specifically while (itrBegin != itrEnd). Is there any way to avoid the call to the if statements?
为了在迭代函数链时避免条件语句,您可以做的一件事是使用链表。然后每个函数都可以无条件地调用下一个函数,您只需将终止逻辑安装为链中的最后一个函数(longjmp 或其他)。或者您可以希望永远不会终止,在列表中包含 glSwapBuffers(或您的图形 API 的等效项)并将其链接回开头。
关于c++ - 迭代而不产生 IF 语句的成本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3895048/
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数
我在用Ruby执行简单任务时遇到了一件奇怪的事情。我只想用每个方法迭代字母表,但迭代在执行中先进行:alfawit=("a".."z")puts"That'sanalphabet:\n\n#{alfawit.each{|litera|putslitera}}"这段代码的结果是:(缩写)abc⋮xyzThat'sanalphabet:a..z知道为什么它会这样工作或者我做错了什么吗?提前致谢。 最佳答案 因为您的each调用被插入到在固定字符串之前执行的字符串文字中。此外,each返回一个Enumerable,实际上您甚至打印它。试试
我正在检查一个Rails项目。在ERubyHTML模板页面上,我看到了这样几行:我不明白为什么不这样写:在这种情况下,||=和ifnil?有什么区别? 最佳答案 在这种特殊情况下没有区别,但可能是出于习惯。每当我看到nil?被使用时,它几乎总是使用不当。在Ruby中,很少有东西在逻辑上是假的,只有文字false和nil是。这意味着像if(!x.nil?)这样的代码几乎总是更好地表示为if(x)除非期望x可能是文字false。我会将其切换为||=false,因为它具有相同的结果,但这在很大程度上取决于偏好。唯一的缺点是赋值会在每次运行
假设我在Ruby中有这个each循环。@list.each{|i|putsiifi>10breakend}我想循环遍历列表直到满足条件。这让我感到“不像Ruby”,因为我是Ruby的新手,是否有Ruby方法可以做到这一点? 最佳答案 您可以使用Enumerable#detect或Enumerable#take_while,取决于您想要的结果。@list.detect{|i|putsii>10}#Returnsthefirstelementgreaterthan10,ornil.正如其他人所指出的,更好的风格是先进行子选择,然后再对其
我注意到类定义,如果我打开classMyClass,并在不覆盖的情况下添加一些东西我仍然得到了之前定义的原始方法。添加的新语句扩充了现有语句。但是对于方法定义,我仍然想要与类定义相同的行为,但是当我打开defmy_method时似乎,def中的现有语句和end被覆盖了,我需要重写一遍。那么有什么方法可以使方法定义的行为与定义相同,类似于super,但不一定是子类? 最佳答案 我想您正在寻找alias_method:classAalias_method:old_func,:funcdeffuncold_func#similartoca
如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:
HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候
在添加一些空格以使代码更具可读性时(与上面的代码对齐),我遇到了这个:classCdefx42endendm=C.new现在这将给出“错误数量的参数”:m.x*m.x这将给出“语法错误,意外的tSTAR,期待$end”:2/m.x*m.x这里的解析器到底发生了什么?我使用Ruby1.9.2和2.1.5进行了测试。 最佳答案 *用于运算符(42*42)和参数解包(myfun*[42,42])。当你这样做时:m.x*m.x2/m.x*m.xRuby将此解释为参数解包,而不是*运算符(即乘法)。如果您不熟悉它,参数解包(有时也称为“spl
我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我