类成员std::vector为何总是触发段错误?
嘿,我一眼就揪出你代码里的致命问题了——未初始化的野指针直接破坏了程序内存结构,这就是为啥你碰任何STL容器都会触发段错误!
具体问题拆解
1. 最致命的野指针问题
在C::readLines函数里,你声明了T* new_t;但完全没初始化它(没写new T()),这玩意儿就是个指向随机内存地址的野指针!然后你直接调用new_t->Active()和new_t->setA(n)——这相当于乱摸内存里的随机区域,直接把程序的内存结构搅乱了,包括你的std::vector内部的控制指针(就是调试时看到的_M_finish和_M_start)。内存被污染后,后续任何操作vector都会触发非法内存访问,直接崩掉。
2. 构造函数里的诡异调用
在C的构造函数里,你写了instance->readLines("a.ini");——这时候instance虽然刚被赋值为当前对象的指针,但构造函数还没执行完啊!虽然这不一定直接崩,但写法非常不规范,直接用this->readLines("a.ini");或者干脆readLines("a.ini");就好。
3. 逻辑上的无效匹配
你用system("echo this is a test command > a.ini");生成的文件内容里,根本没有代码里要找的a:模式,所以readLines里的匹配逻辑根本不会执行到vector操作的部分,但架不住野指针在第一步就已经把内存搞炸了。
一步步修复
第一步:干掉野指针
在readLines函数开头,给new_t初始化内存,推荐用智能指针(符合你代码里的unique_ptr风格):
void C::readLines(const std::string &path) { std::unique_ptr<T> new_t = std::make_unique<T>(); // 自动管理内存,不用手动delete std::ifstream file(path.c_str()); // ... 后续代码 }
如果坚持用原始指针,记得初始化:T* new_t = new T();,但用完要记得释放(还是智能指针香)。
第二步:修正构造函数的调用
把instance->readLines("a.ini");改成:
C::C() { system("echo this is a test command > a.ini"); readLines("a.ini"); // 直接调用就行,不用绕instance }
第三步:让匹配逻辑生效
你生成的a.ini内容和代码里的匹配逻辑不搭,要么修改echo的内容:
system("echo a: test_value > a.ini");
要么调整你的匹配逻辑,让它能识别现有内容。
第四步:规范vector的添加逻辑
当你要把new_t加入t_list时,因为是unique_ptr,直接移动即可:
t_list.push_back(std::move(new_t));
如果用的是原始指针,先封装成unique_ptr再移动:
std::unique_ptr<T> move_t(new_t); t_list.push_back(std::move(move_t));
注意别重复使用已经被移动的指针哦。
额外小建议
- 开启编译器的警告!比如GCC加
-Wall -Wextra -Wpedantic,编译器会直接告诉你new_t未初始化的问题,这类低级错误根本逃不过。 - 尽量少用原始指针,多靠
std::unique_ptr、std::make_unique这类智能指针,能省好多内存管理的坑。 - 你的单例模式可以改得更简洁安全(C++11及以后支持):
C* C::getInstance() { static C instance; return &instance; }
这样不用手动管理init和instance静态变量,还自带线程安全,而且main里的delete c;也可以删掉了——单例的析构会在程序结束时自动处理,手动delete反而会出问题。
内容的提问来源于stack exchange,提问作者user9483299

