basic_string.h不同版本引起的异常崩溃

文章讨论了C++编译宏_GLIBCXX_USE_CXX11_ABI如何影响string和list的版本选择,以及不同设置可能导致的链接问题。作者通过示例展示了如何因为ABI差异导致的编译和链接错误,并解释了C++11中引入__cxx11命名空间的原因。
摘要由CSDN通过智能技术生成

程序运行时报错,查看core文件,发现basic_string.h报错

经过排查发现

编译文件CMakeLists中设置了_GLIBCXX_USE_CXX11_ABI = 0


_GLIBCXX_USE_CXX11_ABI

        是C++中的编译宏, 用来控制string及list使用的版本。 该宏仅在GCC5.1及后续版本中有效。

string及list的新版本符号是std::__cxx11::basic_string 及 std::__cxx11::list。

示例:

#include<string>
void test(std::string &s)
{
    s = "Hello World";
        return;
}

编译使用-D_GLIBCXX_USE_CXX11_ABI=1

test>$ g++ -c -D_GLIBCXX_USE_CXX11_ABI=1 test.c
test>$ nm test.o
0000000000000000 T _Z4testRNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
                 U _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEaSEPKc
                 test(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)
test>$

编译使用-D_GLIBCXX_USE_CXX11_ABI=0

test>$ g++ -c -D_GLIBCXX_USE_CXX11_ABI=0 test.cc
test>$ nm test.o
0000000000000000 T _Z4testRSs
                 U _ZNSsaSEPKc
				test(std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)
test>$

可以看到,-D_GLIBCXX_USE_CXX11_ABI=1 编译后的符号是 std::__cxx11::basic_string,而-D_GLIBCXX_USE_CXX11_ABI=0 编译后的符号是 std::basic_string

string版本不同引发的链接问题

从上节中看到,不同版本的string具有不同的符号。若程序使用了不同版本的库,则会有找不到符号的问题。举例如下:

#include<iostream>
#include<string>

using namespace std;
void a(string s)
{
    cout << s << endl;
    return ;
}

test>$ g++ -c  -D_GLIBCXX_USE_CXX11_ABI=1 a.cc
test>$ nm a.o  | grep " T "
0000000000000000 T _Z1aNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
test>$ c++filt  _Z1aNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
a(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)
test>$

主程序:

#include<iostream>
#include<string>

using namespace std;
void a(string s);
int main()
{
    a("12345");
    return 0;
}

test>$ g++ -c -D_GLIBCXX_USE_CXX11_ABI=0 main.cc
test>$ nm main.o | grep _Z1aSs
                 U _Z1aSs
test>$ c++filt  _Z1aSs
a(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)
test>$

可以看到,main.o依赖的是std::basic_string, 而a.o中是std::__cxx11::basic_string,将main.o与a.o链接起来会找不到符号,如下:

test>$ g++ main.o a.o
main.o:在函数‘main’中:
main.cc:(.text+0x32):对‘a(std::string)’未定义的引用
collect2: 错误:ld 返回 1
test>$

项目中是因为编译的动态库是设置的为-D_GLIBCXX_USE_CXX11_ABI=0 ,但是整个运行主程序是-D_GLIBCXX_USE_CXX11_ABI=1,所以出现开头的崩溃

为什么实现两个版本的string?
        在c++11之前的版本,允许string Copy On Write(即string COW)功能,新的C++11版本禁用了此项功能。在新的 C++11中新增了__cxx11这个命名空间以示区别。
        简单来说, COW 功能是在string对象赋值时, 两个string对象共享内存, 只有在其中一个对象被修改时才会申请新的内存。
        关于string COW功能,看如下的代码:

#include<iostream>
#include<string>

using namespace std;
int main()
{
    string s("str");
    string s1 = s;
    
    char *p = const_cast<char *>(s1.data());
    p[2] = '\0';

    cout << s << endl;
    cout << s1 << endl;

    return 0;
}
// 方式一
test>$ g++  -D_GLIBCXX_USE_CXX11_ABI=1  test.cc
test>$ ./a.out
str
st
// 方式二
test>$ g++  -D_GLIBCXX_USE_CXX11_ABI=0  test.cc
test>$ ./a.out
st
st

可以看到, -D_GLIBCXX_USE_CXX11_ABI=0 编译时修改s1.datas也被改变了, 说明ss1共享了内存。 -D_GLIBCXX_USE_CXX11_ABI=1时 s没改变,说明ss1没有共享内存。

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值