使用C++/CX开发Windows Store应用程序的注意事项

在《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给出了一个例子:

  1. 创建StringReference包装一个缓冲内容。
  2. 调用一个WinRT函数并传递这个StringReference。
  3. 这个WinRT函数触发一个C++回调。
  4. 这个回调修改底层的缓冲内容。
  5. 控制权回到WinRT函数,但字符串已被意外地修改了。

ArrayReference也能类似的用来包装C++数组。但由于WinRT并不期望C++数组是不可变的,于是出现问题的机会比较少。

查看英文原文:Notes on Writing a Windows Store Apps with C++/CX

你可能感兴趣的:(使用C++/CX开发Windows Store应用程序的注意事项)