This article was last updated on <span id="expire-date"></span> days ago, the information described in the article may be outdated.
项目中的一部分实现要求高性能并且稳定,于是准备使用代码分离,高性能和可用性的部分用 C++ 完成,然后编译成 Python 模块,与业务层实现对接。
我在这里使用了 Boost::Python 来进行 C++ 代码的导出。
由于自己在 C++ 方面算是个新手,尤其是在对编译器的工作方面理解的不够深刻,于是在 Linux 中决定自己手动进行编译、链接的工作。果然,第一次编译就喜提了一大堆的 error 与 warning… 我在 MSVC 中赶紧把编译器警告级别提高到了 W4,根据相关的提示信息进行了修改,现在还剩下一个让我十分不解的问题。
1 | class Iterator { |
上面的这一段代码是用来在字节流中格式化出指定的变量,特化的模板函数用于针对 std::string 类型给出结果,在 Windows 平台它工作的很好,编译器没有给出 warning,但当我试图在 gcc 中编译时,却给出了这样的错误:
GCC error: explicit specialization in non-namespace scope
在阅读了上述的解答之后,我知道了,特化的模板函数在 gcc 中是不能直接在类的声明中给出的,需要在类外实现。
1 | template<> inline std::string Iterator::get<std::string>(bool endian, size_t size) { |
经过一番 Debug 之后成功的在 GCC 中编译、链接通过了。
可是在使用 Python 调用时,却出现了 Memory Error
因为工程不算小,我经过了蛮久才定位出了出错的位置:所有调用了这个特化的模板函数的操作都会引起 Memory Error ,而这段代码应该是没什么问题的,因为在 Windows 平台的工作一切正常。
可这又是为什么呢?
模板函数在编译之后和普通函数一样,存在于整个程序的代码区,这部分也是有地址的,代码在调用时其实是调用了函数的地址(指针),将参数入栈进行函数的调用,这部分如果有问题是在编译期间就能发现的;而 Python 这里的 Memory Error 除了内存的 malloc 错误应该就是只对应的函数地址不存在相应的代码。
针对这一点,我便有了一个想法:如果我将函数声明为 inline,在对应的调用地方就会将这段代码进行展开,于是便可能消除这个错误。
我是幸运的,当我将这个成员模板函数声明为 inline 之后,Python 中的调用便成功了。
所以建议大家,如果在 GCC 编译之后,成员模板函数的特化出现了各种奇怪的问题,不妨尝试将函数声明为 inline 来进行 debug;如果函数体较大,可以在 debug 之后删除 inline 标志。
Comments