读Defective C++随笔
不尽知用兵之害者,则不能尽知用兵之利也 ——《孙子兵法》
1.为什么API多用C而不是C++
以前就一直很奇怪,为什么API大都用C的方式提供,即使有C++的接口也只是把C的函数又包一层。既然大家都在用C++的编译器,为什么不直接提供C++的API?当初曾经做过一些编译C++DLL的尝试,印象中只是很麻烦,感觉像是编译器支持不好。其实,最核心的原因在于类的私有成员必须出现在头文件里。每当修改实现时,如果修改了私有成员,那么所有使用该DLL的模块都必须重新编译。这意味着无法独立更新C++API的DLL。而且API库的使用者必须使用和该API库相同的编译器编译,或者被专门设计成能兼容其DLL的编译器(如以前Borland C++的MFC兼容模式)。所以,API大多要么用C,要么用COM式的纯接口。
2.为什么C++程序大多不使用异常
由于C++加入异常功能较晚,绝大大多数的程序采用了C的返回错误码的方式。这些代码不是异常安全的代码,因为它们不能保证在抛出异常时正确释放内存等资源。异常抛出时会跳转到最近的catch语句,后续的资源释放代码将不会执行。要保证异常安全,所有的堆分配对象指针必须使用smart_ptr或shared_ptr等智能指针对象包装,或者用扩展的try-finally语句显示控制释放。而程序员大多不愿引入更多的麻烦,干脆不用异常。但这也带来一些问题,构造函数和重载运算符函数无法返回错误码,所以只能要求它们保证成功。所以便有了构造函数不要做任何资源分配的训诫。不过,即使使用异常,也不能完全解决构造函数运行出错的问题,因为C++规定,构造函数失败,析构函数不会执行。就是说在构造函数抛出异常前分配的资源将无法释放。