RHEL7下GCC8.2编译C++代码出现operator delete链接错误求助
operator delete(void*, unsigned long)未定义引用的问题 我之前碰到好几个开发者在RHEL7上升级GCC后遇到这个问题,正好可以给你梳理下原因和解决办法:
问题根源
GCC 5.x及以后的版本中,libstdc++(GNU的C标准库)引入了带unsigned long参数的operator delete重载,这个重载是为了支持"大小感知"的内存释放优化。而你之前用的GCC 4.8配套的是旧版libstdc,只提供了不带大小参数的operator delete(void*)。
RHEL7默认的系统标准库是和GCC 4.8绑定的,当你用GCC 8.2编译代码时,编译器会生成调用新版operator delete(void*, unsigned long)的指令,但链接阶段还是去找系统旧版的libstdc++,自然找不到这个符号,就报了未定义引用的错误。
可行的解决方案
1. 强制链接GCC 8.2自带的libstdc++
这是最推荐的方案,让编译和链接用同一版本的标准库:
- 如果是静态链接,编译时加上
-static-libstdc++参数 - 如果是动态链接,需要指定GCC 8.2安装目录下的库路径,比如假设你的GCC 8.2装在
/opt/gcc-8.2,编译命令可以改成:g++ -std=c++17 your_code.cpp -L/opt/gcc-8.2/lib64 -Wl,-rpath=/opt/gcc-8.2/lib64-L告诉编译器去哪里找库,-Wl,-rpath则指定程序运行时的库搜索路径。
2. 降级C++编译标准
GCC 8.2默认会用较新的C标准(比如C17),如果你不需要新特性,可以指定和GCC 4.8一致的标准,让编译器生成兼容旧版libstdc++的代码:
g++ -std=c++11 your_code.cpp
这样编译器会调用旧版的operator delete(void*),就能和系统库兼容了。
3. 显式补充缺失的operator delete重载
如果上面两种方案都不适合,你可以在代码中手动实现这个重载,让它调用旧版的delete:
#include <cstdlib> void operator delete(void* ptr, unsigned long size) noexcept { // 直接转发到旧版的无参数delete operator delete(ptr); }
这个方法能快速解决链接错误,但要注意:如果你的代码依赖新版delete的大小优化逻辑,这种转发可能会丢失相关优化,所以只适合临时应急或者确认不需要优化的场景。
补充说明
为什么GCC 4.8编译没问题?因为GCC 4.8的编译器只会生成调用operator delete(void*)的代码,而RHEL7系统的libstdc++正好提供这个符号,所以链接完全正常。
内容的提问来源于stack exchange,提问作者mmm

