C++的一个问题?

程序的目的是统计单个单词在文本中出现在哪些行
程序由5个小文件构成

问个问题,为什么main.cpp中第18行 qr->c 能正常访问(调试中观察到),但是到了print函数后就不正确了?

main.cpp

// main.cpp

#include "TextQuery.h"
#include "QueryResult.h"
#include <fstream>
#include <memory>
#include <stdexcept>
using namespace std;

void runQueries(ifstream &in)
{
    TextQuery tq(in);
    while(true){
        cout << "输入要查寻的字符串,输入q结束:";
        string s;
        if(!(cin >> s) || s == "q")
            break;
        shared_ptr<QueryResult> qr = tq.query(s);
        print(cout, qr);
    }
}

int main()
{
    ifstream in("data/txt.txt");
    if(!in)
        throw runtime_error("打开文件失败");
    runQueries(in);

    return 0;
}

TextQuery.h

// TextQuery.h

#ifndef TEXTQUERY_H
#define TEXTQUERY_H

#include <vector>
#include <string>
#include <map>
#include <set>
#include <fstream>
#include <memory>

class QueryResult;

class TextQuery {
public:
    TextQuery(std::ifstream &in);
    std::shared_ptr<QueryResult> query(const std::string &s);
private:
    std::vector<std::string> v;
    std::map<std::string, std::set<int>> m;
};

#include "QueryResult.h"

#endif

TextQuery.cpp

// TextQuery.cpp

#include "TextQuery.h"
#include "QueryResult.h"
#include <fstream>
#include <string>
#include <sstream>
#include <set>
#include <memory>
using namespace std;

TextQuery::TextQuery(ifstream &in) {
    v.push_back("");
    int l = 1;
    string line;
    while(getline(in, line)) {
        v.push_back(line);
        istringstream iss(line);
        string s;
        while(iss >> s)
            m[s].insert(l);
        ++l;
    }
}

shared_ptr<QueryResult> TextQuery::query(const string &s) {
    shared_ptr<QueryResult> qr = make_shared<QueryResult>(v,s,(m.find(s)==m.end()?set<int>():m[s]));
    return qr;
}

QureyResult.h

// QureyResult.h

#ifndef QUERYRESULT_H
#define QUERYRESULT_H

#include "TextQuery.h"
#include <memory>
#include <string>
#include <set>
#include <vector>
#include <iostream>

class QueryResult {
    friend void print(std::ostream&, std::shared_ptr<QueryResult>);
public:
    QueryResult(std::vector<std::string>& vv, const std::string &strstr, const std::set<int> &s):
            v(vv), str(strstr), c(s) {}
private:
    std::vector<std::string> &v;
    std::string str;
    const std::set<int> &c;
};

#endif

QueryResult.cpp

// QueryResult.cpp

#include "QueryResult.h"
#include <iostream>
#include <memory>
using namespace std;

void print(ostream &os, shared_ptr<QueryResult> qr) {
    os << qr->str << " 出现了 " << qr->c.size() << " 次" <<endl;
    for(const auto &val:qr->c) {
        os << "\t(line " << val << ") " << qr->v[val] << endl;
    }
}

data/txt.txt

Hello a b c
a m d
no Hello
阅读 1.7k
2 个回答

QueryResult常量引用一个脱离了上下文的临时变量,导致print错误

(m.find(s)==m.end()?set<int>():m[s])

这里的set<int>是临时变量,脱离了作用域后会释放.
即在TextQuery::query返回后会析构掉,这时的QueryResult.c指向的是一个无效对象,发生什么事情都是可能的.

改成

shared_ptr<QueryResult> TextQuery::query(const string &s) {
    static const set<int> empty;
    shared_ptr<QueryResult> qr = make_shared<QueryResult>(v,s,(m.find(s)==m.end()?empty:m[s]));
    return qr;
}
shared_ptr<QueryResult> qr = make_shared<QueryResult>(v,s,(m.find(s)==m.end()?set<int>():m[s]));

构造QueryResult的时候find没找到存了局部0变量的引用

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题