有什么建议吗?
编译器给你最好的建议。并非函数中的所有控制路径都包含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()
操作 - 无论是元素没有被抛出的异常删除,或者该功能根本没有效果。
您需要在您的catch块中返回一些值 – 2013-04-23 18:05:51