我只是一个刚起步的程序员,至少比最佳情况下尝试编写更多程序。到目前为止,我一直在阅读Herb Sutter的“Exceptional C++”,并且在异常安全性章节中浏览了三次。但是,除非他提出的示例(堆栈),否则我不确定如何准确地争取异常安全性与速度,以及何时做到这一点完全是愚蠢的。
例如,我当前的家庭作业项目是一个双向链接列表。由于我已经编写了其中的一些程序,因此我想花一些时间来了解一些更深层次的概念,例如ES。
这是我的弹出式功能:
void List::pop_front()
{
if(!head_)
throw std::length_error("Pop front: List is empty.\n");
else
{
ListElem *temp = head_;
head_ = head_->next;
head_->prev = 0;
delete temp;
--size_;
}
}
我对此有些困惑。
1)当列表失败时,我真的应该抛出一个错误吗?我不应该只是不做任何事然后返回,而不是强制列表的用户执行try {] catch(){}语句(这也很慢)。
2)有多个错误类(加上我的老师要求我们在该类中实现的ListException)。这样的事情真的需要自定义错误类吗?是否有关于何时使用特定异常类的一般指南? (例如,范围,长度和边界都听起来一样)
3)我知道在所有引发异常的代码之前,我不应该更改程序状态。这就是为什么我最后减小size_的原因。在这个简单的示例中,这真的必要吗?我知道删除不能抛出。分配给0时head _-> prev是否有可能抛出? (头是第一个节点)
我的push_back函数:
void List::push_back(const T& data)
{
if(!tail_)
{
tail_ = new ListElem(data, 0, 0);
head_ = tail_;
}
else
{
tail_->next = new ListElem(data, 0, tail_);
tail_ = tail_->next;
}
++size_;
}
1)我经常听到在C++程序中任何事情都会失败。测试ListElem的构造函数是否失败(或
new
期间为tail_)是否可行?2)是否有必要测试数据的类型(在我将所有模板化之前,当前为一个简单的
typedef int T
),以确保该类型对于该结构是可行的?我意识到这些都是过于简单的示例,但是目前我对何时应该实际练习良好的ES以及何时不应该练习它感到困惑。
最佳答案
绝对抛出异常。
如果列表为空,用户必须知道发生了什么,否则调试起来会很麻烦。用户是,而不是,被迫使用try/catch语句;如果异常是意外的(即只能由于程序员错误而发生),则没有理由 try catch 它。当未捕获到异常时,它将陷入std::terminate和,这是非常有用的行为。无论如何,try/catch语句本身并不慢。实际抛出异常和释放堆栈的代价是什么。如果不引发异常,则几乎不花费任何费用。
尽可能具体。使用自己的错误类是执行此操作的最佳方法。使用继承对相关异常进行分组(以便调用者可以更轻松地捕获它们)。
如果head_
为null,则取消引用(作为分配给head_->prev
的尝试的一部分)是未定义行为。引发异常是未定义行为的可能结果,但是却是一个不太可能的事件(它要求编译器以一种被认为是荒谬的语言来摆脱握住您的手;)),而不是一个我们担心的是,因为未定义的行为是未定义的行为-这意味着您的程序无论如何已经是错误的,并且试图使错误的方式变得更正确没有任何意义。
另外,您已经在明确检查head_
是否不为null。因此,假设您没有对线程做任何事情,这没有问题。
有点偏执。 :)
如果new
失败,则抛出std::bad_alloc
实例。抛出异常正是您想要在此处发生的事情,因此您不需要或不需要做任何事情-只是让它传播即可。将错误重新描述为某种列表异常并没有真正添加有用的信息,并且可能只会使事情变得更模糊。
如果构造函数ListElem失败,则应该通过抛出异常来使失败,并且也应该让它通过约999到1。
这里的关键是,每当引发异常时,就不会进行清理工作,因为您尚未修改列表以及构造/新建的对象Officially Never Existed(TM),因此没有清理工作。只要确保及其构造函数是异常安全的,就可以了。如果new
调用未能分配内存,则甚至不会调用构造函数。
您需要担心的时间是当您在同一位置中为分配多个分配时。在这种情况下,必须确保如果第二个分配失败,则捕获异常(无论它是什么),清除第一个分配,然后重新抛出。否则,您将泄漏第一个分配。
在编译时检查类型。您实际上无法在运行时对它们做任何事情,也永远不会现实需要。 (如果您不希望进行所有类型检查,那么为什么要使用一种语言来强制您仅在整个地方键入类型名称呢?:))
关于c++ - 异常安全-何时,如何,为什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4482788/