GCC中结合C++20模块使用std::string拼接触发段错误问题
问题原因与修复方案
问题现象
使用g++ 12.2.1编译代码无错误,但运行时触发Segmentation fault (core dumped);移除构造函数初始化列表中的三条字符串初始化语句后,错误消失。
相关代码如下:
主程序test_main.cpp
import shared_buffer; namespace sb = shared_buffer; struct DataRecord { int i; }; int main () { sb::Handle <DataRecord, 10> handle ("my_handle"); return 0; }
模块shared_buffer.cpp
export module shared_buffer; import <string>; import <iostream>; namespace st = std; export namespace shared_buffer { template <typename Record, int maxNrOfRecords> struct Content { int size = 0; Record records [maxNrOfRecords]; }; template <typename Record, int maxNrOfRecords> class Handle { public: st::string name; st::string mutexName ; st::string memoryName; Content <Record, maxNrOfRecords> content; Handle (st::string name): // 添加这3行触发段错误 name (name), mutexName (name + "_mutex"), memoryName (name + "_memory") { st::cout << name << '\n'; st::cout << mutexName << '\n'; st::cout << memoryName << '\n'; } }; }
编译脚本compile
clear g++ -std=c++20 -fmodules-ts -xc++-system-header string g++ -std=c++20 -fmodules-ts -xc++-system-header iostream g++ -std=c++20 -fmodules-ts shared_buffer.cpp test_main.cpp
问题原因
构造函数的参数名name与类成员变量name重名,在初始化列表中:
name(name)会被编译器解析为用未初始化的成员变量name初始化自身,此时成员变量还未完成构造,处于非法内存状态。- 后续
mutexName (name + "_mutex")和memoryName (name + "_memory")中的name,访问的是未初始化的成员变量而非构造函数参数,对未初始化的std::string执行拼接操作属于未定义行为,直接触发段错误。
修复方案
修改构造函数的参数名,避免与成员变量重名,比如将参数改为_name,再用参数初始化成员:
修改后的Handle类构造函数部分:
Handle (st::string _name): name (_name), mutexName (_name + "_mutex"), memoryName (_name + "_memory") { st::cout << name << '\n'; st::cout << mutexName << '\n'; st::cout << memoryName << '\n'; }
也可以通过this->name明确指定成员变量,用参数初始化(推荐结合std::move减少拷贝):
Handle (st::string name): name (std::move(name)), mutexName (this->name + "_mutex"), memoryName (this->name + "_memory") { st::cout << name << '\n'; st::cout << mutexName << '\n'; st::cout << memoryName << '\n'; }
前者代码更直观,能从根源避免命名歧义,是更推荐的写法。
内容的提问来源于stack exchange,提问作者Jacques de Hooge
相关产品推荐
相关产品推荐

