如果cond如何避免。用于堆栈操作

时间:2010-10-21 07:16:48

标签: c++

我创建了一个包含std :: vector的堆栈类。我编写了像pop()和exch()之类的堆栈操作,如

int Stack::pop() 
{
  if (v.size() < 0)
    throw("Error : Stack Underflow");

  int tos = v.back();
  stack.erase(v.end()-1);
  return tos;
}

void Stack::exch()  // Exchange top 2 element
{
  if (v.size() < 2)
    throw("Error : Stack Underflow");

  size_t n = v.size();
  int tmp = v[n-1];
  v[n-1] = v[n-2];
  v[n-2] = tmp;
}

我的应用程序包含很多'pop()'和'exch()'运作。但由于'if'条件,性能有点慢。 你能告诉我如何避免“如果”的条件吗? 有没有办法或努力避免'如果'。

提前致谢。

谢谢, Nilesh制作

7 个答案:

答案 0 :(得分:2)

不,不是真的。如果你需要检查,你必须检查。您可以使用三元运算符替换if,但几乎可以肯定地编译为相同的代码。

除非size()方法特别复杂,否则我无法看到它拖累性能那么多。你可以 通过缓存Stack类中的值来提高速度(我假设v是某种向量)。

但是,如果它一个向量,它完全能够自己作为一个堆栈,所以你可以让它自己引发异常,而不是强加你的例外。

您唯一缺少的是exch方法,您可以这样做:

a = v.back(); v.pop_back();
b = v.back(); v.pop_back();
v.push_back(a);
v.push_back(b);

答案 1 :(得分:1)

你说检查条件相当于执行成本的很大一部分。问题是抛出异常还是if本身是最高的成本。如果成本与实际抛出异常的情况相关联,那么您可能希望重构代码以使其无异常(返回代码似乎是一个很好的选择),因为异常是昂贵的。另外,请注意异常可能会产生很小的影响,即使它们没有被抛出 - 即。如果抛出异常,编译器必须跟踪在堆栈展开期间要销毁的对象集。编译器很聪明,所以期望成本很小,但不是零。

另一方面,如果不抛出异常,但成本确实与错误预测相关联,那么您可能希望返回到编译器供应商文档并查看如何提示它。许多编译器允许进行两阶段编译,在第一次编译之后,您可以运行测试和配置文件,并且可以将该分析信息交还给编译器,以便在知道应用程序的预期行为的情况下优化代码。 / p>

手动地,您还可以提示编译器关于检查的最期望结果是什么。特别是,一些编译器会假设if的最可能结果是成功(输入if,跳过else),并且最可能的代码路径将进入if。还有一些特殊的关键字可用于提示编译器,例如,在gcc中,您可以使用if (__builtin_expect( (condition), 0 ))告诉编译器最可能的结果是condition为假。

答案 2 :(得分:0)

您的if语句不是性能问题。在分析算法时,您可以将决策语句视为常量,或者换句话说,不会影响性能。这并不是说如果你有一些代码if (SomeExpensiveFn() == AnotherExpensiveFn()),那么if部分(即结果的比较)不会忽略不计。

只有在不重新评估整个集合时才会这样。虽然1到n if语句不是性能问题。如果堆栈类导致N ^ 2 if if语句将被执行,那么您将看到性能下降。

此外,我认为这是作业,但如果不是std::stack

答案 3 :(得分:0)

如果您知道即将进行N pop()而无需推送,则可以在客户端代码中对size()进行一次检查,然后呼叫新的unsafe_pop()成员不检查的功能。同样,当您的客户端代码可以更有效地保证足够的元素时,您可以拥有unsafe_exch()

但是,这里其他操作的费用会使if语句相形见绌...甚至擦除的指针算法(end() - 1)可能需要10倍的时间。如果你的性能需求是那么极端,你应该看得更深,还有替代算法,线程/并发等等。

答案 4 :(得分:0)

将if / throw更改为断言

答案 5 :(得分:0)

不,你不能删除if语句。
但是如果你以某种方式删除“抛出”,你可以稍微提高性能。抛出和捕获异常是一个缓慢的操作(如果您对以下内容感兴趣:http://www.codeproject.com/KB/cpp/exceptionhandler.aspx)。

所以,在Stack::exch()中你可以放return而不是throw..。如果您想知道交换是否成功完成,您可以创建函数bool并检查truefalse

但是你无法为弹出操作做任何事情。

此外,您可以更改v.size() < 0(顺便说一下,此必须v.size() <**=**0,或者您可以尝试从空堆栈中popif( ! v.empty() )

修改: 你可以这样编写这些函数:

int Stack::pop() 
{
    if ( v.empty() )
    {
        throw( "Error : Stack Underflow" );
    }

    int tos = v.back();
    stack.erase( v.end() - 1 );
    return tos;
 }

bool Stack::exch()  // Exchange top 2 element
{
    if( v.size() < 2 )
    {
        return false;
    }

    std::vector< int >::size_type n = v.size();

    int nTmp = v[ n - 1 ];
    v[ n - 1 ] = v [ n - 2 ];
    v[ n - 2 ] = nTmp;

    return true;
}

答案 6 :(得分:0)

STL容器与您自己的代码的混合使我想知道您为什么不使用std::stack? 坚持一个选择。 例如,代码中的弹出操作可以简单如下:

int Stack::pop() 
{
  if (size == 0)
    throw("Error : Stack Underflow");

  int tos = v[size-1];
  --size;  
  return tos;
}

void Stack::exch()  // Exchange top 2 element
{
  if (size < 2)
    throw("Error : Stack Underflow");

  std::swap(v[size-1], v[size-2]);
}