Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/159.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 功能速度提前终止或在结束时终止_C++_Performance_Visual Studio - Fatal编程技术网

C++ 功能速度提前终止或在结束时终止

C++ 功能速度提前终止或在结束时终止,c++,performance,visual-studio,C++,Performance,Visual Studio,在编写函数时,似乎总是有两个阵营 希望在函数中找到1的返回(通常在末尾) 喜欢线性数据流(通常具有多个回报)的人 通常这是个人风格,但我想谈谈表现。 在我提问之前,让我先提出一个假设情景: 假设需求说明: Function should first try to calc ReturnVal based off of A. (Typical Case) If A is unable to be determined then try to find based off of B. If B i

在编写函数时,似乎总是有两个阵营

  • 希望在函数中找到1的返回(通常在末尾)
  • 喜欢线性数据流(通常具有多个回报)的人
  • 通常这是个人风格,但我想谈谈表现。 在我提问之前,让我先提出一个假设情景:

    假设需求说明:

    Function should first try to calc ReturnVal based off of A. (Typical Case)
    If A is unable to be determined then try to find based off of B. 
    If B is unable to be determined then try to find based off of C. 
    If all else fails then return C since that is always known.
    Function should return enum which states which way the value was found.
    
    因此,假设我们有以下几点:

    enum HowFound
    {
      eWithA,
      eWithB,
      eWithC
    };
    
    HowFound CalcReturn(int& nValue) const;
    
    我的问题 就速度(JMP的数量等)而言,您认为编译器在大多数情况下可以更好地优化哪种风格

    风格1

    HowFound CalcReturn(int& nValue) const
    {
      HowFound howFound = eWithA;
    
      const int valWithB = CalcWithB();
      const int valWithC = CalcWithC();
    
      nValue = CalcWithA( valWithB, valWithC );
      if (nValue == -1)
      {
        nValue = valWithB;
        howFound = eWithB;
        if (nValue == -1)
        {
           nValue = valWithC;
           howFound = eWithC;
        }
      }
    
      return howFound; 
    }
    
    对于样式1,您存储返回值,并且从不提前终止函数。您有一个位于末尾的返回

    风格2

    HowFound CalcReturn(int& nValue) const
    {
      const int valWithB = CalcWithB();
      const int valWithC = CalcWithC();
    
      nValue = CalcWithA( valWithB, valWithC );
      if (nValue != -1)
      {
        return eWithA;
      }
    
      if (valWithB != -1)
      {
        nValue = valWithB;
        return eWithB;
      }
    
      nValue = valWithC;
      return eWithC;
    }
    
    对于样式2,数据流更“线性”。一旦找到该值,就退出该函数。这意味着函数中有更多的终止点

    免责声明:显然,每种风格都可以进行一些调整,但我的问题仍然是一样的。此外,是的,我可以编写这两个函数并检查反汇编(我有),但随着更多“细节”的添加,结果会发生变化。我的问题是哪种风格更有可能表现得更好(如果有的话)


    谢谢

    在大多数情况下,编译器将为这两种样式生成相同的代码,尽管我注意到您的特定实现可能效率较低(最公平的比较是在
    else
    s中赋值;您的赋值然后重新赋值)


    但是,当然,编译器可能会有所不同。

    编译器会将两个示例翻译成相同的代码。它更多的是关于“哪个更容易阅读”[这实际上取决于您的代码如何匹配算法的实际描述]


    编辑:我应该说“任何像样的、优化的编译器”——一个非常初级的、优化不好的编译器实际上可以完全按照您的要求执行,而无需重新安排任何内容,从而在一种情况下比另一种情况更好/更差。但是,只要您没有故意编写代码,使其不必要地执行冗长的操作(例如,对长字符串调用strlen(),或者调用is_prime(101218819)或类似的东西,然后不使用该值,您应该会得到相同的结果)。和往常一样,如果你知道这是你的代码的一个重要部分[基于评测],那么一定要尝试一下你的项目使用的编译器和设置,看看它是否有什么不同-和往常一样,在互联网上询问并不能代替对代码关键部分进行基准测试

    好吧,尽管编译器所做的优化有很多不同,但这两种代码都将被简化为效率大致相同的代码。因此,执行时间将大致相同。但是,如果您正在寻找时钟周期节省,您应该测试它。在这种情况下,故事不会就此结束。它还取决于硬件优化,尤其是分支预测器。因此,如果您对值的频率和所采用的路径有了概念,并且希望在时钟周期级别进行保存,那么重构代码以适应路径将有所帮助。如果你不想看这个,那就看可读性吧

    由于以下原因,这个问题似乎可能不合适:

    • 没有实际的问题需要解决:“我很好奇别人是否和我一样。”
    • 这是一个伪装成问题的咆哮:“糟透了,我说得对吗?”
    除此之外,OP也没有真正考虑这个问题

    这是第三种款式吗

     HowFound CalcReturn(int& nValue) const
     {
       const int valWithB = CalcWithB();
       const int valWithC = CalcWithC();
       HowFound howFound = eWithC;
       nValue = CalcWithA( valWithB, valWithC );
       if (nValue != -1)
       {
         howFound= eWithA;
       }
       else if (valWithB != -1)
       {
         nValue = valWithB;
         howFound = eWithB;
       } 
       else {
         nValue = valWithC;
       }
       return howFound;
     }
    
    这是A型还是B型?它似乎是线性的,不管是什么样的线性直觉。它有1个返回,并且很可能所有3个函数都编译成相同的代码。尽管使用了一些现代编译器,但NRVO在使用单个出口点时工作得更好(例4)

    我增加了还是减少了复杂性

    这是快还是慢

    我还可以用多少其他方法转换此代码

    如何确定哪个更易于维护

    我可以说,一个函数到另一个函数的每一次转换只返回1次,必然会使代码变得同样复杂或更复杂吗

    更复杂到底意味着什么


    其中有些问题是开放式的…

    你试过分析这些问题吗?a)没有区别。b) 不,这不是风格的问题。来自1号阵营的人们根本不理解C++中的编程是如何工作的,我不同意C++的风格资源管理。@我同意有一些关于样式1的争论,但是在一般情况下,方法2的优点显然超过了它的缺点:当函数更自然地表示为多个出口导致更复杂时,将一个函数重组为单出口。代码。这基本上是决定性的论据。@thang-增加函数的复杂性以使其更易于调试?!但这也不会使调试变得更难吗?@安全性问题。问题是关于C++的。如果你使用C++而不使用RAII,那么你就做错了,你应该感觉不好。虽然它可能被表述得不清楚,但我确实试着把它包含在需求中。请注意“(典型情况)”,如最高概率。@BabelFish上述答案有两部分。首先是一般情况。第二种情况下,您需要节省时钟周期。如果您想了解一般情况,请忽略第二部分。我想补充一件关于一般优化的事情。现在的编译器非常聪明。它们被设计成压缩所有可能的优化。您的代码并不复杂。因此,大多数编译器将生成同样高效的代码。因此,对于上面的代码,请考虑可读性。选择一个与逻辑匹配的代码,因为代码或多或少会像注释一样相同(即使传递相互测试视图)。