调用C++库时unordered_map触发Segmentation fault问题求助
排查C++ Trie实现中的Segmentation Fault问题
我在Python中调用修改后的C++ Trie自动补全代码时,持续触发Segmentation fault (core dumped)错误,经定位错误出现在unordered_map的children.count(remaining_w.at(0))语句,恳请帮忙排查原因。
完整代码
C++ 实现代码
#include <iostream> #include <unordered_map> #include <string> #include <fstream> #include <unordered_set> #include <vector> #include <sstream> #include <typeinfo> using namespace std; // using namespace std::chrono; class trie{ public: string word; unordered_map<char, trie*> children; // this function works // with the argument flag set to zero int insert(string w, int flag, string remaining_w = ""){ //the first time we call insert if(flag == 0) remaining_w = w; int the_size = remaining_w.size(); if(children.count(remaining_w.at(0)) == 0){ children[remaining_w.at(0)] = new trie(); } if(the_size == 0){ word = w; return 0; }else{ //the recursive calls with flag one children[remaining_w.at(0)]->insert(w, 1, remaining_w.erase(0, 1)); return 0; } } }; class AutoCorrect{ public: // The tree trie tree; //the dictionary with the words const int max_cost = 2; const int too_big_distance = 10; void insert(char* word){ ifstream ifp(word); while(ifp >> word){ cout << word <<endl; tree.insert(word, 0); // } } } void test(char* test){ cout << test << endl; } void search_recursive(trie* p_tree, char ch, const string& word, vector<int>& previous_row, int max_cost, unordered_map <string, int>& results) { int sz = previous_row.size(); int min_row = 12; vector<int> current_row(sz, too_big_distance); current_row[0] = previous_row[0] + 1; // Calculate the min cost of insertion, deletion, match or substution int insert_or_del, replace; for (int i = 1; i < sz; i++) { insert_or_del = min(current_row[i-1] + 1, previous_row[i] + 1); replace = (word[i-1] == ch) ? previous_row[i-1] : (previous_row[i-1] + 1); current_row[i] = min(insert_or_del, replace); } if ((current_row[sz-1] <= max_cost) && (p_tree->word != "")) { results[p_tree->word] = current_row[sz-1]; } for(auto& it: current_row){ if (it < min_row) min_row = it; } if(min_row <= max_cost){ for(auto& it: p_tree->children){ search_recursive(it.second, it.first, word, current_row, max_cost, results); } } } int search(string word) { unordered_map <string, int> results; int sz = word.size(); vector<int> current_row(sz + 1); for (int i = 0; i <= sz; ++i){ current_row[i] = i; } for(auto& it: tree.children){ search_recursive(it.second, it.first, word, current_row, max_cost, results); } for(auto& p:results) cout << p.first << ", " << p.second << endl; return 0; } }; // The cost and a distance for vector initialization extern "C" { AutoCorrect* AutoCorrect_new(){ return new AutoCorrect(); } void AutoCorrect_insert(AutoCorrect* autocorrect, char* word){ autocorrect->insert(word); } void AutoCorrect_search(AutoCorrect* autocorrect, string input_word){ autocorrect->search(input_word); } void AutoCorrect_test(AutoCorrect* autocorrect, char* name){ autocorrect-> test(name); } }
Python 调用代码
from ctypes import cdll lib = cdll.LoadLibrary('autocorrect.so') class AutoCorrect(object): def __init__(self): self.obj = lib.AutoCorrect_new() def insert(self, word): lib.AutoCorrect_insert(self.obj,word) def search(self,input_word): lib.AutoCorrect_search(self.obj,input_word) def test(self,test): lib.AutoCorrect_test(self.obj,test) if __name__ == "__main__": import json WordCount = 0 autocorrect = AutoCorrect() data_dir = "some_txt_file.txt" autocorrect.insert(bytes(str(data_dir), encoding='utf8'))
问题原因分析及修复方案
1. Trie插入函数的字符串越界问题
这是触发段错误的直接原因:
- 在
trie::insert函数中,代码先执行children.count(remaining_w.at(0)),之后才判断the_size == 0。当remaining_w为空字符串时,remaining_w.at(0)会直接抛出std::out_of_range异常,进而导致程序崩溃(段错误)。 - 修复逻辑:调整判断顺序,先检查字符串是否为空,再执行后续操作:
int insert(string w, int flag, string remaining_w = ""){ if(flag == 0) remaining_w = w; int the_size = remaining_w.size(); // 先判断字符串是否为空,避免越界访问 if(the_size == 0){ word = w; return 0; } if(children.count(remaining_w.at(0)) == 0){ children[remaining_w.at(0)] = new trie(); } // 递归插入剩余字符 children[remaining_w.at(0)]->insert(w, 1, remaining_w.erase(0, 1)); return 0; }
2. AutoCorrect::insert的缓冲区溢出问题
- 函数参数
char* word被同时用作文件名和读取单词的缓冲区,当读取的单词长度超过原指针指向的内存空间时,会发生缓冲区溢出,破坏内存结构,导致后续操作出现不可预测的错误(包括段错误)。 - 修复方案:使用
std::string接收读取的单词:
void insert(char* filename){ ifstream ifp(filename); string word; // 用string安全接收单词 while(ifp >> word){ cout << word << endl; tree.insert(word, 0); } }
同时注意修改extern "C"中的对应函数声明,保持参数一致。
3. C++与Python交互的类型不匹配问题
extern "C"中的AutoCorrect_search函数参数使用std::string,但C语言没有该类型,Python的ctypes无法正确传递参数,会导致内存错误。- 修复方案:将参数改为
char*,内部转换为std::string:
// C++端修改 void AutoCorrect_search(AutoCorrect* autocorrect, char* input_word){ autocorrect->search(string(input_word)); } // Python端调用时直接传字符串(ctypes会自动转为char*) def search(self, input_word): lib.AutoCorrect_search(self.obj, input_word.encode('utf8'))
4. 额外的内存泄漏风险
- 当前代码中
trie节点使用new创建,但没有对应的delete操作,长期运行会导致内存泄漏。建议后续添加析构函数,递归销毁所有子节点。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

