当前位置: 首页 > 知识库问答 >
问题:

如何从文档中确定函数可以引发哪种类型的异常?

越学文
2023-03-14

我是C编程的新手,但我已经用一些高级语言编程了一段时间,所以我可以找到大多数文档的方式。我正在学习C中的异常处理,特别是通过这个例子:

vector<int> myNums;

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

现在,这段代码没有捕捉到异常,因为。resize()方法不是< code>bad_alloc,而是< code>length_error。我的问题是,通过查看这些文档,您是如何做到这一点的?也许我漏掉了一些明显的东西。

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

中提到的唯一特定异常是bad_alloc。有人能告诉我如何知道<code>length_error

共有3个答案

邵劲
2023-03-14

你需要挖一点才能找到它。

我将使用留档在cp首选项,它在跟踪标准中发生的事情方面做得相当不错。(标准是权威来源,但标准随着时间的推移而发展)。

根据https://en.cppreference.com/w/cpp/container/vector,的说法,html" target="_blank">实例化向量时的第二个模板参数是分配器类型,默认为< code>std::allocator

因为分配器是默认的,所以在用户代码中不经常显式地引用它(大多数开发人员不需要使用非默认分配器)。

但是

std::vector<int> myNums;

实际上相当于

std::vector<int, std::allocator<int> > myNums;

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

std::vector的内存分配实际上由其reserve()member函数处理。该功能的文档位于https://en.cppreference.com/w/cpp/container/vector/reserve声明如果<code>new_cap,则抛出<code>std::length_error

这是一个提示,但是我们可以通过挖掘https://en.cppreference.com/w/cpp/memory/allocator的默认分配器和它的()成员函数的留档来获得更具体的信息https://en.cppreference.com/w/cpp/memory/allocator/allocate这表明如果分配失败,该函数将抛出std::bad_alloc

司迪
2023-03-14

从https://cplusplus.com/reference/vector/vector/resize/,开始,如果您有像您这样的案例,您可能会特别注意本文档页面上列出的案例,其中指出:

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

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

这里你可以读到向量::保留接受一个参数new_cap,它决定向量的新容量。当new_cap时,它会抛出length_error

我给出这一系列的步骤,并不是因为我认为任何人在每次写代码的时候都会/应该被期望在文档中挖掘这么多。只是因为您想知道是什么步骤导致了抛出的异常。

我同意,如果< code>resize的文档能够涵盖所有情况下抛出异常的所有基础,那会好得多。不幸的是,这在文档方面太常见了。

戈安翔
2023-03-14

这种情况并不少见。多年来,该语言的复杂性增加了很多,积累了对C标准的多次修订,甚至C标准本身有时也可能与自身相悖。

让我们看看C标准本身对重载的< code>resize() vector方法的两个版本是怎么说的。我手边正好有一份N4860的副本,基本上是C 20版本,在查找C标准本身关于< code>resize()的异常的说明时,我发现两个< code>resize()重载将它们的异常行为定义如下:

constexpr void resize(size_type sz);

// ...

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

// ...

constexpr void resize(size_type sz, const T

// ...

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

这是< code>resize()中唯一提到的异常。我在< code>vector本身和“容器要求”中找不到更一般的内容,也没有找到关于异常保证的讨论,但是没有关于vector的< code>resize()或< code>reserve()的具体细节。

这是一个明显的疏忽。很明显,当涉及到可能由于重新分配而产生的异常时,两种重载应该具有相同的异常行为。第一个重载的描述直接从它前面的< code>reserve()中提取。不用说,< code>resize()使用< code>reserve()在需要时增加vector的容量,并继承其异常保证/行为。

但第二个<code>resize()</code>重载也必须如此。它们之间唯一的区别是,一个默认值在向量增长时构造新值,另一个复制值构造新值。但就重新分配期间的异常行为而言,它们必须是相同的。与异常相关的两个重载之间的总体差异是由于值的默认构造函数和/或其复制/移动构造函数之间的任何异常差异。

我的问题是,通过查看这些文档,您是如何做到这一点的?

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

通过研究关于所讨论的类、模板或算法的一切,理解它必须如何工作——即< code>resize()从< code>reserve()继承它们行为的某些部分——然后得出不可避免的推论,您就可以到达您想要的地方。

TLDR:就是这样。

 类似资料:
  • 问题内容: 当我尝试使用RaiseError时,出现以下编译问题 消息443,级别16,状态14,过程ConvertSessionToCurr,第19行在函数中无效使用了副作用运算符’RAISERROR’。 那么我们如何处理函数中的异常/将其更改为out参数存储的proc?听起来真是太可惜了! 问题答案: 选项: 返回NULL或一些前哨值 使用存储过程 使其内联代码 我的想法是,如果您在UDF中需

  • 问题内容: 允许构造函数抛出异常吗? 问题答案: 是的,构造函数可以引发异常。通常,这意味着新对象可以立即进行垃圾回收(当然,尽管一段时间内可能不会收集到)。如果“半构造”对象在构造函数中较早可见(例如,通过分配静态字段或将其自身添加到集合中),则可能会留下痕迹。 在构造函数中引发异常时要注意的一件事:由于调用者(通常)将无法使用新对象,因此构造函数应注意避免获取非托管资源(文件句柄等),然后引发

  • 问题内容: 如何从枚举构造函数中引发异常?例如: 产生错误 未处理的异常类型IOException 问题答案: 由于实例是在静态初始化程序中创建的,因此请抛出ExceptionInInitializerError。

  • 向客户端浏览器中输出中文一直是很多初学者最闹心的问题之一。如果按着输出英文的方式输出中文,往往会在浏览器中出现乱码或是干脆乱码都不出现,直接显示成了“?”。但如果要是了解了显示乱码或“?”的原理,那么处理起这类问题,就会游刃有余了。       首先来看一下为什么会显示“?”。当在浏览器中出现“?”时,查看一下HTML源代码,这时就会发现在HTML源代码中仍然是“?”,从这一点可以断定。显示“?”

  • 问题内容: 我想用一个新版本来更新该图,其中还包括新的HTML5元素。但是,似乎没有HTML5 DTD。看来嵌套规则是由HTML5中定义的各种内容模型定义的。 所以没有DTD,对吗? 后续问题: HTML5中没有DTD的原因吗?DTD是为所有不同类型的元素定义嵌套规则的好方法。他们为什么不包括这样的东西? 问题答案: 没有HTML5 DTD。HTML5 RC 在讨论XHTML序列化时明确指出了这一

  • 我为一个更大的应用程序构建了一个库/模块,它从一个函数中抛出一个异常。如果找不到文件或者文件包含错误的格式,就会抛出异常。 该方法类似于: 异常将终止我的模块,因为它将被捕获在使用我的模块的应用程序中,但没关系,因为格式不好。 我想知道的是——像这样从递归函数中抛出异常是一种不好的做法吗?