C++ C++;noexcept用于未引发异常的函数,但可能导致内存故障
例如,有两种不同的方法访问私有数组的元素是很常见的,一种是重载数组订阅运算符,另一种是在处定义C++ C++;noexcept用于未引发异常的函数,但可能导致内存故障,c++,noexcept,C++,Noexcept,例如,有两种不同的方法访问私有数组的元素是很常见的,一种是重载数组订阅运算符,另一种是在处定义: T& operator[](size_t i) { return v[i]; } T const& operator[](size_t i) const { return v[i]; } T& at(size_t i) { if (i >= length) throw out_of_range("You shall not pass!");
:
T& operator[](size_t i) { return v[i]; }
T const& operator[](size_t i) const { return v[i]; }
T& at(size_t i)
{
if (i >= length)
throw out_of_range("You shall not pass!");
return v[i];
}
T const& at(size_t i) const
{
if (i >= length)
throw out_of_range("You shall not pass!");
return v[i];
}
at
版本的可以引发异常,但数组订阅运算符不能
我的问题是,尽管操作符[]
不会引发异常,但它是否可以标记为noexcept
,即使知道它会引发SIGSEGV信号,还是仅仅是一种不好的做法
我想指出一个信号(如SIGSEGV)不是一个例外。作为对noexcept
含义的字面解释,noexcept
函数声明它不会抛出异常。它没有说明任何其他内容(包括信号)
但是,一个noexcept
函数比这更有意义,至少对我代码的客户来说是这样noexcept
还隐式表示函数是安全的,它将在没有计算错误的情况下完成其执行
因此,将noexcept
标记为不安全的函数是否不合适?一个选项是添加边界检查,并使超出范围的值执行一些有意义的操作,例如返回last,如下所示
T& operator[](size_t i)
{
static T default;
if (i >= length && length > 0)
{
return v[length - 1];
}
else if (i >= length && length == 0)
{
return default;
}
return v[i];
}
这是不标准的,但在我看来,如果你清楚地记录了行为,这是可以接受的。这允许无例外和无信号保证。这是一个棘手的问题,并提出了其中涉及的一些关键问题,即,我将尝试在这里引用最低限度(强调我的):
在这篇文章中,我想分享一下我对使用noexcept真正增加价值的地方的观察。它的出现频率比人们预期的要低,它与抛出或不抛出异常没有多大关系。这个结论让我有点吃惊[很强],我不愿意提出它,因为它与我从权威人士身上听到的关于这个问题的意见相反。p>
以及:
考虑到对noexcept的这种消极态度,它能被认为是有用的吗?对noexcept特性在C++11中引入得很晚,以解决移动语义的一个特殊问题。道格拉斯·格雷戈(Douglas Gregor)和大卫·亚伯拉罕(David Abrahams)在这里描述了这一点
然后他继续给出了一个不寻常的移动分配定义,并认为我们真正想要传达的不是它不会抛出异常,而是它不会失败,但这是一个非常困难的问题,但它是出于真正的意图:
[…]这是因为noexcept真正想要的信息
传达的是功能永不失效;并不是说它从不扔!我们
从上面可以看出,函数可以失败,但仍然不能抛出,但是
仍然符合noexcept(false)的条件。也许关键字应该有
被称为诺法尔。“永不失效”担保不能由供应商进行检查
编译器(与任何其他故障安全保证非常相似),因此
我们唯一能做的就是申报
这是一个更普遍的观察的一部分,我们是什么
真正感兴趣的是程序组件中的故障安全,而不是
而不是例外安全。无论是否使用异常,都会返回错误
价值观,错误还是什么
除此之外,关于基本(无泄漏、保持不变)、强(提交或回滚)和永不失败保证的推理应该仍然成立
因此,如果我们采取类似的立场,那么答案似乎是否定的,如果不适合使用noexcept
,这似乎就是你所倾向的。我认为这不是一个明确的答案
他还指出。这反过来又是我们的基础。本文件对窄合同和宽合同的定义与N3248相同:
广泛合同
一项功能或操作的广泛契约并不
指定任何未定义的行为。这种合同没有任何先决条件:
具有广泛契约的函数不会放置额外的运行时
对其参数、任何对象状态或任何外部
全球国家。具有广泛合同的职能示例如下:
vector::begin()和vector::at(大小\类型)。例子
没有广泛约定的函数将是vector::front()和
向量::运算符[](大小\类型)
狭义合约
狭义合同是指不宽泛的合同。狭义合同
函数或操作在中调用时会导致未定义的行为
违反书面合同的方式。这样的合同
指定至少一个涉及其参数、对象的前提条件
状态,或某些外部全局状态,例如
静态对象。标准函数的好例子
契约是vector::front()和vector::operator[](大小\类型)
并建议:
每个图书馆职能部门都有LWG同意的广泛合同
无法抛出,应标记为无条件noexcept
并意味着具有狭义契约的函数不应是
noexcept,该函数的备份说明:
[…]这些设计考虑凌驾于我们针对狭义合同功能的一般政策之上。[……]
因此,如果我们想保持保守并遵循标准库实践,那么似乎由于
操作符[]
没有广泛的契约,因此不应该将其标记为noexcept事实:无论您是否使用noexcept,函数仍然可以抛出SIGSEGV
现在,我认为答案是主观的,取决于个人观点。您对noexcept函数的期望是什么?您是否希望它永远不会失败(即使noexcept不提供此类保证)?与“安全”函数相比,您将如何处理非安全函数?这个项目会有很大的不同吗?如果你的答案是肯定的,那么你可能