通过对象创建的另一个C ++奇怪的分段错误

时间:2016-05-10 19:30:02

标签: c++ object

我最近在c ++对象创建中遇到了问题。这个问题有点像问题 C++ strange segmentation fault by object creation ,但这里的代码是开源项目的一部分,可能没有简单的错误。

在方法中调用对象创建,并且通过两个连续步骤调用该方法。

该类在strtokenizer.h中定义如下:

class strtokenizer {
    protected:
        vector<string> tokens;
        int idx;
    public:
        strtokenizer(string str, string seperators = " ");
        void parse(string str, string seperators);
        int count_tokens();
        string next_token();   
        void start_scan();
        string token(int i);
};

在strtokenizer.cpp中,就像这样:

using namespace std;
strtokenizer::strtokenizer(string str, string seperators) {
    parse(str, seperators);
}
void strtokenizer::parse(string str, string seperators) {
    int n = str.length();
    int start, stop;
    if (flag) {
        printf("%d\n", n);
    }
    start = str.find_first_not_of(seperators);
    while (start >= 0 && start < n) {
        stop = str.find_first_of(seperators, start);
        if (stop < 0 || stop > n) {
            stop = n;
        }
        tokens.push_back(str.substr(start, stop - start));
        start = str.find_first_not_of(seperators, stop + 1);
    }
    start_scan();
}
int strtokenizer::count_tokens() {
    return tokens.size();
}
void strtokenizer::start_scan() {
    idx = 0;
    return;
}
string strtokenizer::next_token() {
    if (idx >= 0 && idx < tokens.size()) {
        return tokens[idx++];
    } else {
        return "";
    }
}
string strtokenizer::token(int i) {
    if (i >= 0 && i < tokens.size()) {
        return tokens[i];
    } else {
        return "";
    }
}

创建strtokenizer对象的方法如下:

int dataset::read_wordmap(string wordmapfile, mapword2id * pword2id) {
    pword2id->clear();
    FILE * fin = fopen(wordmapfile.c_str(), "r");
    if (!fin) {
        printf("Cannot open file %s to read!\n", wordmapfile.c_str());
        return 1;
    }
    char buff[BUFF_SIZE_SHORT];
    string line;
    fgets(buff, BUFF_SIZE_SHORT - 1, fin);
    int nwords = atoi(buff);
    for (int i = 0; i < nwords; i++) {
        fgets(buff, BUFF_SIZE_SHORT - 1, fin);
        line = buff;
        strtokenizer strtok(line, " \t\r\n");
        if (strtok->count_tokens() != 2) {
            continue;
        }
        pword2id->insert(pair<string, int>(strtok->token(0), atoi(strtok->token(1).c_str())));
    }
fclose(fin);
return 0;

}

首次运行read_wordmap()方法时(第一次调用read_wordmap()),&#39; strtok&#39;对象创建大约87k次,在第二次(第二次read_wordmap()调用),该对象预计运行超过88k次。但是,在第二个方法调用中,它会在以下行中引发错误(有时&#39;分段错误&#39;有时&#39;内存损坏(快速)&#39;)约86k次:

strtokenizer strtok(line, " \t\r\n");

当对象创建的代码块被修改为如下所示时,将没有错误。

strtokenizer *strtok = new strtokenizer(line, " \t\r\n");
printf("line: %s", line.c_str());
if (strtok->count_tokens() != 2) {
    continue;
}
pword2id->insert(pair<string, int>(strtok->token(0), atoi(strtok->token(1).c_str())));

2 个答案:

答案 0 :(得分:0)

您的代码中看起来有内存损坏。您应该考虑使用像valgrind(http://valgrind.org/)这样的工具来检查代码是否写出超出范围。

您修改后的代码使用堆内存而不是堆栈内存,这可能会隐藏问题(即使它仍然存在)。

通过阅读您的代码,在提供的wordmapfile有一些意外数据的情况下,有几个缺失的测试可确保安全处理。 例如,你不检查fgets的结果,所以如果文件开头的单词数大于实际单词数,你就会遇到问题。

答案 1 :(得分:0)

我在@Paul R和其他朋友的建议下仔细调试了我的代码,发现这是因为我没有堆栈中的空闲内存。 上面提出的代码是我项目的一小部分,在项目中,gibbs采样算法应该运行一千次(迭代)。

在每次迭代中,旧矩阵应该被释放,新的矩阵将被“新出”。但是,我忘了释放所有矩阵和列表,这就是我的程序破坏的原因。

我上面发布代码的原因是每次遇到代码时程序都会崩溃:

strtokenizer strtok(line, " \t\r\n");

对象“strtok”将在文件中运行1000 *行(10000+行)。所以它让我觉得可能创建了太多的对象并占用了所有的堆栈内存。即使我发现没有必要手动释放它们。

在visual studio中调试程序时,内存占用率监视器在每次迭代中都显示出急剧增长,并且偶尔发生“bad_alloc”错误。这些让我意识到我忘了释放一些大的动态矩阵。

谢谢大家! 我为错误描述的占用你时间的问题道歉!