2013-04-23 104 views
3

Ive得到的代码是给我在编译如下警告短位:并非所有控制路径都返回一个值?警告:

“BGOLUB ::容器::堆栈::流行”:不是所有的控制路径返回一个值

下面是代码:

template<typename T> 
T Stack<T>::Pop()                   
{ 

try 
{ 
    if (m_index<0) throw OutOfBoundsException(m_index); 

    --m_index; 
    return(m_array[m_index]); 
} 

catch(OutOfBoundsException&) 
{ 
    cerr<<"Underflow Index = "<<m_index<<endl; 
} 

catch(...) 
{ 
    cerr<<"Unhandled Error Occured"<<endl; 
} 
} 

有什么建议?

非常感谢!

+0

您需要在您的catch块中返回一些值 – 2013-04-23 18:05:51

回答

18

有什么建议吗?

编译器给你最好的建议。并非函数中的所有控制路径都包含return语句,并且函数应该返回一个值。

如果抛出异常并且控制权被转移到catch处理程序,那么该处理程序将打印一些内容到cerr,然后在函数的末尾流出,而实际上并不需要任何东西。

这是未定义的行为。根据C++ 11标准的第6.6.3/2段:

[..]流出函数结尾等于没有值的返回; 这会导致在返回值函数中出现未定义的 行为。

对于默认constructible值,可以通过正确的函数结束前添加一个return T()声明解决这个问题:然而

template<typename T> 
T Stack<T>::Pop() 
{ 
    try 
    { 
     // ... 
    } 
    catch (OutOfBoundsException&) 
    { 
     // ... 
    } 
    catch (...) 
    { 
     // ... 
    } 

    return T(); 
// ^^^^^^^^^^^ 
} 

较为合理的做法是,以Pop()吞下例外,而是重新抛出它Pop()没有就如何从错误中恢复的战略级的信息发生在这种情况下:

template<typename T> 
T Stack<T>::Pop() 
{ 
    try 
    { 
     // ... 
    } 
    catch (OutOfBoundsException&) 
    { 
     // ... 
     throw; // <== Re-throw after printing the diagnostic 
    } 
    catch (...) 
    { 
     // ... 
     throw; // <== Re-throw after printing the diagnostic 
    } 
} 

更妙的是,如果用于记录一个错误信息的责任不属于Pop()可言,因为Pop()是在某种意义上可能会被不同需求的代码重复使用(有些可能不想记录任何内容,有些可能希望将消息记录到文件中,有些可能希望以不同的语言记录消息,等等)。

所以你的功能更合理的版本实际上是:

template<typename T> 
T Stack<T>::Pop()     
{ 
    if (m_index<0) throw OutOfBoundsException(m_index); 
    --m_index; 
    return(m_array[m_index]); 
} 

在一般情况下,你应该尝试(没有双关语意),以避免try/catch块,除非你有:

  • 翻译一个例外
  • 从错误中恢复(但你需要这样做的战略知识)

如果这不是你的任务(如上面的函数Pop()),在大多数情况下,最好的办法是不会处理所有的异常并让它们向上传播调用堆栈。

引述Dave Abrahams

经常处理异常的最好的办法是无法处理它们。如果你可以让他们通过你的代码,并允许析构函数来处理清理,你的代码将变得更清晰。

为了避免内存泄露,资源,或一般职责,编写代码,使用适当的RAII包装异常安全。这种意义上的优秀指导原则在this two-part talk by Jon Kalb中给出。

特别是,避免编写catch (...)处理程序:发明异常是为了防止程序员忽略错误,并在通用处理程序中吞并它们而不重新抛出它们是忽略它们的最佳方式。


注:

注意,您的Pop()实施是一个有点问题:如果拷贝构造函数或移动的T构造会发生什么返回元素时返回给调用者抛出,之后你已经修改了堆栈指针?

这就是为什么C++标准库定义了两个独立的功能pop()top():因为它允许提供有力保障,即给事务语义你pop()操作 - 无论是元素没有被抛出的异常删除,或者该功能根本没有效果。

+0

要展开最后一点:捕获异常,以便处理它。记录错误不处理它。 – 2013-04-23 18:12:22

+0

@sftrabbit:是的,一般处理或翻译。但是你是对的,日志不能处理。我应该澄清这一点,谢谢 – 2013-04-23 18:13:28

+3

优秀的答案。 – 2013-04-23 18:16:16

1

您需要重新抛出异常,或者在函数结束时返回可能的T()。

1

当引发异常时,它将被两个catch语句之一捕获。但是,他们仍然需要return这个函数的一个值。你可以在你的函数的最后放置一个return声明。

但是,如果Pop由于Stack为空而引发异常,让异常传播出函数更有意义。为什么Pop本身试图处理特殊情况?

0

我会建议在所有的if声明中使用括号,即使是单行的机构也是如此。它们不是绝对必要的,你可以在没有它们的情况下编写完全合法的代码,但它们使你的代码更加可读,像这样的错误将更容易找到。

此外,看起来你对于例外如何工作有一个基本的误解。如果您的代码遇到异常,它将直接跳转到catch块,并且不会执行try块中的任何后续代码。因此,try块中的return语句块将永远不会到达,并且您的函数不会返回任何内容,因为catch块没有return语句。

您可以通过在catch块中添加return语句来解决此问题。

相关问题