C++11 ABI下能否在同一文件中混合使用std::string与std::__cxx11::string
解决方案
方案1:单编译单元内显式混用双ABI类型(更简洁,无需额外编译包装层)
你可以在全局保留默认_GLIBCXX_USE_CXX11_ABI=1的编译选项,无需为了兼容旧闭源库修改全局配置,只需手动显式声明两种ABI的字符串类型即可:
// 显式声明旧ABI字符串类型,对应_GLIBCXX_USE_CXX11_ABI=0时的std::string using old_string = std::basic_string<char, std::char_traits<char>, std::allocator<char>>; // 新版C++11 ABI字符串就是当前编译模式下默认的std::string using new_string = std::string;
libstdc++的库文件本身同时包含两种ABI的STL类型实现,只是默认编译选项只会导出对应版本的命名空间别名,因此上述声明合法可直接使用。
之后只需要实现两个简单的转换函数,在调用闭源库前后做类型转换即可:
// C++11 ABI转旧ABI old_string to_old(const new_string& s) { return old_string(s.data(), s.size()); } // 旧ABI转C++11 ABI new_string to_new(const old_string& s) { return new_string(s.data(), s.size()); }
使用示例:
// 调用闭源库的old_abi_func接口,入参和返回值都是旧ABI的std::string new_string input = "test input"; old_string old_input = to_old(input); old_string old_output = old_abi_func(old_input); new_string output = to_new(old_output);
该方案注意事项:
- 不要跨ABI边界传递STL对象的引用、指针,也不要让不同ABI的STL对象互相赋值、析构,仅通过拷贝原始数据的方式做转换即可保证安全
- 若闭源库还用到其他STL类型(如
std::vector、std::list),也可以用同样的方式显式声明旧ABI版本的类型,再做内容拷贝转换
方案2:独立封装C接口库(兼容性最好,适合复杂场景)
也就是你目前在用的方案,将所有对旧ABI闭源库的调用封装到一个独立的编译单元中,该单元单独用_GLIBCXX_USE_CXX11_ABI=0编译,对外暴露的接口全部使用C兼容类型(const char*、基础数值类型、不透明指针等)。
这个方案的优势是完全避免ABI泄漏风险,即使闭源库用到大量自定义STL类型也不会和主项目的C++11 ABI产生冲突,长期维护成本更低。
说明
你之前理解的「_GLIBCXX_USE_CXX11_ABI设为1时无法访问旧ABI类型」是误解:宏开关只控制std命名空间下默认导出的STL类型别名,两种ABI的实现一直都存在于libstdc++.so中,完全可以通过显式指定完整类型名的方式访问旧ABI版本。
内容的提问来源于stack exchange,提问作者Irfy
相关产品推荐
相关产品推荐

