Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/162.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么C++;0x';是否动态检查s`noexcept`?_C++_Exception_C++11 - Fatal编程技术网

C++ 为什么C++;0x';是否动态检查s`noexcept`?

C++ 为什么C++;0x';是否动态检查s`noexcept`?,c++,exception,c++11,C++,Exception,C++11,我很好奇这本书中noexcept背后的原理throw(X)被弃用,但是noexcept似乎也做了同样的事情。编译时没有检查noexcept有什么原因吗?如果静态地检查这些函数,它们只调用try块中的抛出函数,似乎会更好。如果我记得throw已被弃用,因为无法指定模板函数可以抛出的所有异常。即使对于非模板函数,您也需要throw子句,因为您添加了一些跟踪 另一方面,编译器可以优化不抛出异常的代码。有关详细讨论,请参见“”(以及部分和)。要点似乎是: 过去二十年的大量经验表明,在实践中,只有两种形式

我很好奇这本书中
noexcept
背后的原理
throw(X)
被弃用,但是
noexcept
似乎也做了同样的事情。编译时没有检查
noexcept
有什么原因吗?如果静态地检查这些函数,它们只调用
try
块中的抛出函数,似乎会更好。

如果我记得throw已被弃用,因为无法指定模板函数可以抛出的所有异常。即使对于非模板函数,您也需要throw子句,因为您添加了一些跟踪

另一方面,编译器可以优化不抛出异常的代码。有关详细讨论,请参见“”(以及部分和)。要点似乎是:

过去二十年的大量经验表明,在实践中,只有两种形式的例外规范是有用的:

  • 缺少公开异常规范,该规范指定可以引发任何类型异常的函数:

    int func(); //might throw any exception
    
  • 一个从不抛出的函数。这种函数可以通过throw()规范表示:

    int add(int, int) throw(); //should never throw any exception
    

请注意,
noexcept
检查应用于
null
指针的失败的
dynamic_cast
typeid
引发的异常,这只能在运行时完成。其他测试确实可以在编译时完成。

考虑一个函数

void fn() noexcept
{
   foo();
   bar();
}
你能静态检查它是否正确吗?您必须知道foo或bar是否会抛出异常。您可以强制所有函数调用位于try{}块内,类似这样

void fun() noexcept
{
    try
    {
         foo();
         bar();
    }
    catch(ExceptionType &)
    {
    }
}
但这是错误的。我们无法知道foo和bar只会抛出这种类型的异常。为了确保我们捕捉到任何我们需要使用“…”的东西。如果你发现了什么,你将如何处理你发现的错误?如果这里出现意外错误,唯一要做的就是中止程序。但这基本上就是默认情况下提供的运行时检查所要做的


简而言之,如果提供足够的细节来证明给定函数永远不会抛出不正确的异常,那么在编译器无法确定该函数是否会抛出错误类型的情况下,就会产生冗长的代码。静态证明的有用性可能不值得付出努力。

noexcept和
throw()
的功能有一些重叠,但它们实际上来自相反的方向

throw()
是关于正确性,而不是其他:一种在引发意外异常时指定行为的方法


noexcept
的主要目的是优化:它允许/鼓励编译器围绕不会抛出异常的假设进行优化


但是,是的,实际上,它们是同一事物的两个不同名称。不过,它们背后的动机是不同的。

正如其他答案所述,诸如
dynamic\u cast
s之类的语句可能会抛出,但只能在运行时检查,因此编译器在编译时无法确定

这意味着在编译时,编译器可以让它们离开(即,不进行编译时检查)、发出警告或直接拒绝(这是没有用的)。这使得警告成为编译器唯一合理的操作

但这仍然不是很有用——假设您有一个
动态\u cast
,无论出于何种原因,它都不会失败并抛出异常,因为您的程序是这样编写的。编译器可能不知道这一点,并抛出一个警告,它变成了噪声,可能只是因为没有用而被程序员禁用,否定了警告的意义

类似的问题是,如果您有一个未使用
noexcept
指定的函数(即,可以抛出异常),您希望从许多函数调用该函数,有些是
noexcept
,有些不是。您知道该函数永远不会抛出由
noexcept
函数调用的情况,但编译器也不会:更多无用的警告


因此,编译器在编译时没有有效的方法来强制执行这一点。这更多的是在静态分析领域,它往往更挑剔,并对这类事情发出警告。

基本上,这是一个链接器问题,标准委员会不愿意打破ABI。(如果由我决定,我会这么做,它真正需要的只是库的重新编译,我们已经有了线程启用的情况,而且是可以管理的。)

考虑一下结果会如何。假设要求是

  • 每个析构函数都隐式
    noexcept(true)
    • 可以说,这应该是一项严格的要求。抛出析构函数总是一个错误
  • 每个外部“C”都隐式
    noexcept(true)
    • 同样的论点:C-land中的异常总是一个bug
  • 除非另有规定,否则其他每个函数都隐式
    noexcept(false)
  • noexcept(true)
    函数必须将其所有
    noexcept(false)
    调用包装在
    try{}catch(…){}
    • 通过类比,常量方法不能调用非常量方法
  • 在重载解析、函数指针兼容性等方面,此属性必须以不同的类型显示
  • 听起来很合理,对吧

    为了实现这一点,链接器需要区分函数的
    noexcept(true)
    noexcept(false)
    版本,就像可以重载成员函数的const和const版本一样

    那么,这对名字Namming意味着什么呢?为了与现有的目标代码向后兼容,我们需要将所有现有名称解释为带有额外manglin的
    noexcept(false)