如何从文档中确定函数可以抛出什么类型的异常?

Ada*_*leb 34 c++ exception

我是 C++ 编程新手,但已经使用高级语言进行编程,可以找到解决大多数文档的方法。我正在学习 C++ 中的异常处理,特别是通过以下示例:

vector<int> myNums;

try
{
    myNums.resize(myNums.max_size() + 1);
}
catch (const bad_alloc& err)
{
    cout << err.what() << endl;
}
Run Code Online (Sandbox Code Playgroud)

此代码不会捕获异常,因为 .resize() 方法抛出的异常不是bad_alloc;它是length_error。那么,从这个文档中,您如何实现这一点呢?也许我错过了一些明显的事情。

https://cplusplus.com/reference/vector/vector/resize/

其中提到的唯一具体例外是bad_alloc. 有人可以告诉我如何从该页面开始知道这length_error是正确的例外吗?

Sam*_*hik 31

这并不罕见。多年来,该语言的复杂性已大大增加,对 C++ 标准进行了多次修订,有时甚至连 C++ 标准本身也可能出现矛盾。

让我们看看 C++ 标准本身对重载resize()向量方法的两个版本有何规定。我碰巧手边有一份 N4860 的副本,它基本上是 C++20 版本,在查找 C++ 标准本身对resize()异常的说明时,我发现这两个resize()重载定义了它们的异常行为,如下所示:

constexpr void 调整大小(size_type sz);

// ...

备注: 如果异常是由非 Cpp17CopyInsertable T 的移动构造函数引发的,则不会有任何影响。

// ...

constexpr void resize(size_type sz, const T& c);

// ...

备注:如果抛出异常,则不会产生任何影响。

这是 中唯一提到的例外情况resize()。我没有发现任何更一般性的内容vector,在“容器要求”中也没有发现任何关于异常保证的讨论,但没有涉及向量resize()或的具体细节reserve()

这是一个明显的疏忽。很明显,当涉及到可能因重新分配而生成的异常时,两个重载应该具有相同的异常行为。第一个重载的描述直接取自reserve()其之前的描述。不言而喻,它resize()用于reserve()在需要时增加向量的容量,并继承其异常保证/行为。

但对于第二次过载来说,同样的情况也必须成立resize()。它们之间的唯一区别是,一种在向量增长时默认构造新值,另一种则进行复制构造。但就重新分配期间的异常行为而言,它们必须相同。两个重载之间与异常相关的总体差异是由于值的默认构造函数和/或其复制/移动构造函数之间的任何异常差异造成的。

我的问题是,通过查看此文档,您如何做到这一点?> 也许我错过了一些明显的事情。

不,你没有错过任何东西。C++标准本身存在一些差距;更不用说像您正在查看的那样的第二手文档来​​源了。

resize()通过研究有关类、模板或算法的所有内容,了解它们必须如何工作(即继承其行为的某些部分reserve()),然后得出不可避免的推论,您就可以到达您想要去的地方。

TLDR:就是这样。

  • 只有经验才能给出答案…… (8认同)

小智 8

https://cplusplus.com/reference/vector/vector/resize/开始,如果您有像 Push 这样的情况max_size(),您可能会特别注意此文档页面上列出的情况,其中指出:

如果 n 也大于当前容器容量,则会自动重新分配已分配的存储空间。

由于您的箱子绝对会大于当前的集装箱容量,因此这可能值得研究。此文本块中链接的是容量的文档页面:https ://cplusplus.com/reference/vector/vector/capacity/ 。从容量页面中,您会看到vector::reserve用于显式增加向量的容量。由于您的情况max_size() + 1肯定会涉及增加向量容量,因此您可能会怀疑涉及此功能。因此,您可以转到文档页面:https://en.cppreference.com/w/cpp/container/vector/reserve

在这里您会读到它vector::reserve采用一个参数new_cap来确定向量的新容量。length_error当 时它会抛出new_cap > max_size()

我给出这一系列步骤并不是因为我认为任何人在每次编写代码时都会/应该通过文档挖掘这么多内容。只是因为您好奇哪些步骤可能导致您抛出异常。

我同意,如果文档resize涵盖了所有情况下抛出异常的所有基础,那就更好了。不幸的是,这对于文档来说太常见了。


Pet*_*ter 8

你需要挖掘一下才能找到它。

我将使用 cppreference 上的文档,它在跟踪标准中发生的情况方面做得相当不错。(标准是权威来源,但标准随着时间的推移而演变)。

根据https://en.cppreference.com/w/cpp/container/vector,实例化向量时的第二个模板参数是分配器类型,默认为std::allocator<T>(其中T是向量的元素类型)。

由于分配器是默认的,因此通常不会在用户代码中显式引用(大多数开发人员不需要使用非默认分配器)。

std::vector<int> myNums;
Run Code Online (Sandbox Code Playgroud)

实际上相当于

std::vector<int, std::allocator<int> > myNums;
Run Code Online (Sandbox Code Playgroud)

vectors成员函数的规范resize()描述了它抛出时会发生什么,但没有描述它将抛出的情况 - 或它可能抛出的内容。

for 的内存分配std::vector实际上是由它的reserve()成员函数处理的。https://en.cppreference.com/w/cpp/container/vector/reserve上该函数的文档指出,它会抛出std::length_errorifnew_cap > max_size()或由Allocator::allocate()(通常是std::bad_alloc)引发的任何异常。 Allocator是上面提到的第二个模板参数的名称。

这是一个提示,但我们可以通过深入研究默认分配器的文档( https://en.cppreference.com/w/cpp/memory/allocator )及其allocate()成员函数(https://en)来获得更具体的信息。 cppreference.com/w/cpp/memory/allocator/allocate显示std::bad_alloc如果分配失败,函数将抛出异常。