在《Diving deep into C++ /CX and WinRT》演讲里,Marian Luparu谈到针对Windows 8的应用程序的异常处理和性能问题。对于开发者来说,最重要的东西是理解WinRT和标准C++代码之间的边界如何影响异常处理和性能。
\异常处理基础
\WinRT没有异常的概念,它的内部使用HResult。放在Platform::Exception的派生类之内的调试信息不会跨越ABI边界。通常和异常相关的信息只对调试器可用。
\C++和SEH风格的异常会在跨越ABI边界的时候中止进程。这意味着所有C++异常都需要处理,即使这意味着只是把它包装到Platform::Exception里。
\在捕获COMException时一定要检查HResult。如果你不知道如何处理某个HResult,可以重新抛出这个异常。类似的,如果你调用一个COM方法,它返回一个错误代码,你应该马上把它转换成一个Exception。
\异步和异常处理
\在使用并行模式库(PPL)时,让Lambda表达式接受一个task对象而不是一个单纯的结果是很重要的。比如说,应该使用
\\.then( [](Task result) {…} )\
而不是
\\.then( [](int result) {…} )\
如果你使用第二个版本,一旦遇到异常,整个“then”代码块就会被忽略。(译注:关于PPL的异步可以参考《遇见PPL:C++的并行和异步》的第四节《async + continuation》)
\异步和线程
\和C#以及VB里的async/await一样,PPL在处理线程时有点繁琐。如果你在UI线程里开始一项操作,那么每个continuation(即“then”代码块)也将在UI线程里执行。如果你想使用线程池,你需要向“then”方法传递task_continuation_context::use_arbitrary参数。
\C++类 vs WinRT类
\一般而言,开发者不应该适用WinRT风格的类(ref class),除非他们要和XAML交互或者向其他语言提供WinRT组件而不得不这样做。WinRT类比标准C++类慢,而且不能移植,即无法在标准C++应用程序里使用。
\另一个改善性能的途径是减少WinRT类型和C++类型之间的转换。虽然频繁的跨越WinRT边界的通讯会很慢,但没有必要的分配内存和复制数据可能更糟。
\一些诸如StringReference的包装类或许能够缓解性能问题,但使用的时候必须非常小心。StringReference是引用计数的,因此,在StringReference释放之前,它包装的缓冲内容不能被改变或者删除。这个问题会在WinRT持有StringReference的一个副本时出现,你无法预料会出现什么结果。Marian Luparu给出了一个例子:
\- 创建StringReference包装一个缓冲内容。\
- 调用一个WinRT函数并传递这个StringReference。\
- 这个WinRT函数触发一个C++回调。\
- 这个回调修改底层的缓冲内容。\
- 控制权回到WinRT函数,但字符串已被意外地修改了。\
ArrayReference也能类似的用来包装C++数组。但由于WinRT并不期望C++数组是不可变的,于是出现问题的机会比较少。
\
本文探讨了在Windows 8环境下使用C++/CX及WinRT进行应用程序开发时面临的异常处理与性能问题。重点讲解了WinRT与标准C++间的异常处理差异、异步编程中的注意事项以及如何通过减少类型转换来提升性能。
5万+

被折叠的 条评论
为什么被折叠?



