0

作为对这个问题的跟进,我的前两件事仍然是异常处理程序是一件好事吗?一方面,它做了很多例外。另一方面,这是在 sdl 中,这意味着它可能尽可能优化,这意味着我的其他功能非常快。所以...

这是运行大约 64 秒后程序配置文件的顶部,在我做了一些优化之后

Flat profile:

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total           
 time   seconds   seconds    calls   s/call   s/call  name    
  8.32      3.39     3.39                             _Unwind_SjLj_Register
  6.77      6.15     2.76                             _Unwind_SjLj_Unregister
  6.28      8.71     2.56  4000006     0.00     0.00  CAST128::setkey(std::string)
  3.73     10.23     1.52                             std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()
  3.61     11.70     1.47                             __dynamic_cast
  3.56     13.15     1.45 64000080     0.00     0.00  CAST128::F(int&, unsigned int&, unsigned int&, unsigned char&)
  3.26     14.48     1.33                             std::string::_Rep::_S_create(unsigned int, unsigned int, std::allocator<char> const&)
  3.09     15.74     1.26                             std::istreambuf_iterator<char, std::char_traits<char> > std::num_get<char, std::istreambuf_iterator<char, std::char_traits<char> > >::_M_extract_int<unsigned long long>(std::istreambuf_iterator<char, std::char_traits<char> >, std::istreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, std::_Ios_Iostate&, unsigned long long&) const
  2.94     16.94     1.20                             std::string::compare(char const*) const
  2.32     17.89     0.94  4002455     0.00     0.00  unhexlify(std::string)
  2.06     18.73     0.84                             std::string::operator[](unsigned int)
  2.01     19.55     0.82 32037245     0.00     0.00  std::string makehex<int>(int, unsigned int)
  1.94     20.34     0.79                             std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned int)
  1.91     21.11     0.78                             operator new(unsigned int)
  1.87     21.88     0.76                             std::string::append(std::string const&)

cast128 运行了 100000 次,这就解释了为什么它在顶部

4

2 回答 2

1

这些不是异常处理程序,而是用于通知异常处理程序在抛出异常时需要调用的析构函数的函数。例如,考虑

for (int i = 0; i < 1000000; ++i) {
    std::string stuff; // or any type with a non-trivial destructor
    function();        // maybe with arguments that depend on "stuff"

    // inline code using "stuff" here
}

每次迭代,都会创建和销毁字符串,并且每次都必须在异常处理程序中注册和注销,以防function()抛出异常。您可以通过各种方式避免这种开销,具体取决于对象的使用方式:

  • 如果对象(或从它创建的任何东西)没有传递给函数,则在函数调用之后移动它的定义
  • 声明function(以及它调用的任何函数)inline,以便从与对象相同的堆栈帧中抛出任何异常;我相信只要函数实际上是内联的,就不需要注册对象
  • 确保function不会抛出异常,并throw()为其添加规范
  • 将对象移出循环,clear()在每次迭代开始时重新初始化(或在我的示例中调用)(这也将消除创建和销毁它的开销)
于 2011-06-30T17:39:37.290 回答
1

出于本次讨论的目的,我将 try/catch 和 ctor/dtor 混为​​一谈。

在 C++ 中,可以在第一个使用点声明一个变量。在 C 语言中,可以通过在声明前添加一个大括号来获得相同的效果,但代价是函数末尾有大量右大括号。

在 C++ 中,变量的声明要求调用其构造函数,并在超出范围时调用其析构函数,或者在其范围的物理结束之前引发异常。(对于 POD 类型,ctor 和 dtor 被省略。)

早期的 C++ 实现为每个作用域注册了全局析构函数栈。后来的实现使它成为线程本地的析构函数堆栈。随后的实现在每个函数附近发出描述性信息,以便程序计数器和堆栈指针的组合可以暗示当抛出异常时需要执行哪些析构函数。

在某些系统上,PC/SP 组合是不够的,或者难以解释。iOS 设备有 ARM 处理器,而 ARM 有两种指令形式——手臂和拇指。我怀疑一个人可能能够回溯堆栈以确定调用链的某些方面,但不能有效可靠地确定每个方面使用的指令集,因此 PC/SP + 数据方法也一样棘手。

因此,iOS 使用基于 SjLj 的异常。它们由 libunwind 实现。在 iOS 5.0 之前,该实现存在一些性能问题(参见http://www.em.net/portfolio/2012/06/unwind_sjlj_top_items_in_profi.html)。

iOS 5.0 提供了一个可行的最佳实现。

于 2012-06-26T03:40:52.557 回答