【问题标题】:Does throw() (i.e. __declspec(nothrow)) give real benefits in Visual C++?throw() (即 __declspec(nothrow)) 是否在 Visual C++ 中提供了真正的好处?
【发布时间】:2012-05-20 12:46:05
【问题描述】:

专注于 Visual C++,您是否曾在使用 throw()(即 __declspec(nothrow))非抛出规范的 C++ 代码中体验过显着的性能提升? 它真的对优化器有帮助吗? 是否有任何基准显示性能提升?

我在网上找到了不同的(相反的)建议:

Boost exception-specification rationale反对throw(),相反,Larry Osterman 在他的博文中似乎赞成Why add a throw() to your methods?

(我想澄清一下,我对 VC++ 特定代码感兴趣;我知道在 GCC 中,由于运行时检查,throw() 规范实际上可能是“悲观化” .)

P.S. 阅读ATL标头,发现throw()被普遍使用;此外,我在this MSDN article 中找到了一个方便的C++ RAII unique_handle 类,它也使用throw() 规范。

【问题讨论】:

  • 这真的与你自己的设计有关,如果你的函数有理由抛出一些东西,那么就这样做,只要记住异常是针对特殊情况,而不是错误。就使用异常的运行时间而言,大部分争论是关于异常传播到处理程序所需的时间,以及对异常进行的额外运行时间检查。唉,如果你写的东西对性能非常重要,你可能会考虑根本不使用异常。但是对于大多数非关键代码,异常使用是可以的。这只是我的两分钱。
  • 这是相当主观的。但是你给出的例子是相反的,Boost 担心异常规范只是不能很好地工作。 C++11 委员会同意并弃用它们。 Larry 正在谈论编译器可以利用它们生成更优化代码的方式,这是一个完全不同的角度。可以工作,但我厌倦了优化器智取我提供一个例子。由于 64 位代码使用函数表,因此优化非常轻微并且变得非常无关紧要。
  • 不要考虑微观性能,要考虑清晰度。
  • 他的问题是关于性能,而不是什么是好的设计。我也很想知道这方面的答案!
  • @Cheersandhth.-Alf:如果您编写的组件在应用程序中使用了很多时间,那么小的优化可能会增加一些重要的东西。我发现 throw() 在 ATL 标头中普遍使用,它也用于 unique_handlein this MSDN article

标签: c++ visual-c++ exception


【解决方案1】:

我添加了它,但它不是为了帮助优化器,而是为了帮助我编写更正确的代码。

class X
{
    public:
        void swap(X& rhs) throw(); // Swap better not ever throw
                                    // If it does there is something else
                                    // much more seriously wrong
};

【讨论】:

  • 我认为你有一个错字:throws() 应该是throw()
  • 哎呀。这就是当你编写而不编译时会发生的情况。
【解决方案2】:

throw() 的主要问题是标记为throw() 的函数内的代码可以 抛出。 例如,这将完美地工作:

void foo() throw()
{
    throw "haha\n";
}

int main()
{
    try {
        foo();
    }
    catch(const char* s) {
        std::cout << s;
    }
    return 0;
}

请注意,foo 不会 throwmain,原因。而且您不会捕获异常(就像您评论 throw() 说明符一样)。相反,编译器将使用 try{}catch() 块包装代码函数。当生成异常时,它将由全局处理程序处理(这意味着您的程序默认崩溃)。

注意,编译器必须try{}cath()块包装函数代码,除非编译器确定,否则内部代码不可能产生异常。

因此,可以使用foo调用者 进行一些优化,但事情变得更加复杂内部 foo

编辑:

__declspec(nothrow) 不一样:如Microsft tells

这个属性告诉编译器声明的函数和 它调用的函数从不抛出异常。

这意味着,编译器可以省略 try{}catch() 包装代码。

EDIT2 实际上,微软违反了标准行为,不会为throw() 生成warpper。好吧,那你可以使用throw()来提升性能。

【讨论】:

  • 在 MSVC 中,throw() 在语义上等价于 __declspec(nothrow)。
【解决方案3】:

MSVC 编译器将其视为优化提示,是的。

Boost 必须是跨平台的,它们必须在各种编译器上寻找安全且高效的东西。正如 boost 文档所说,当指定 throw() 时,一些编译器可能会生成较慢的代码,并且在许多情况下,编译器可以推断出不会抛出异常无论是否有一个 throw() 规范,所以对于 Boost,最安全的方法是永远不要使用 throw-specifications。

但是,如果您专门针对 MSVC,那么throw() 会有效地告诉编译器不要为函数生成异常处理代码,这可能会在函数过于复杂而编译器无法确定的情况下加速不会抛出异常。

【讨论】:

  • 那么,对于一个简单的非抛出 getter,添加 throw() 会没用吗?
  • 很有可能。当然,要确定,您必须对其进行测试。它可能取决于其他一些因素。如果 getter 在不同的编译单元中定义,编译器在调用它时将不知道它做了什么,或者它是否会抛出。所以,throw() 可能仍然会有所作为。
猜你喜欢
  • 1970-01-01
  • 2012-02-20
  • 2011-03-04
  • 2011-01-16
  • 2010-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-10
相关资源
最近更新 更多