C++ Primer书上这个例子讲的很不错,写写帮助自己理解标准库和智能指针。
.h 文件内容
#include <fstream> #include <iostream> #include <vector> #include <string> #include <map> #include <set> #include <sstream> #include <memory> class QueryResult; class TextQuery { public: using line_no = std::vector<std::string>::size_type; TextQuery(std::ifstream& ifs); // 返回string的信息 QueryResult query(const std::string&) const; private: std::shared_ptr<std::vector<std::string>> words_file; std::map<std::string, std::shared_ptr<std::set<line_no>>> wm; }; class QueryResult { friend std::ostream& print(std::ostream&, const QueryResult&); public: QueryResult(std::string s, std::shared_ptr<std::vector<std::string>> wf, std::shared_ptr<std::set<size_t>> l) : sought(s), file(wf), lines(l){} private: std::string sought; // 要查询的单词 std::shared_ptr<std::vector<std::string>> file; // 输入文件 std::shared_ptr<std::set<size_t>> lines; // 保存出现的行号 };
.cpp 文件内容
#include "TextQuery.h" TextQuery::TextQuery(std::ifstream& ifs) : words_file(new std::vector<std::string>) { std::string text; while (getline(ifs, text)){ words_file->push_back(text); // 记录当前行号 size_t n = words_file->size() - 1; // 获取每行每个单词 std::istringstream line(text); std::string word; while (line >> word){ auto &ckeck = wm[word]; if (nullptr == ckeck) ckeck.reset(new std::set<line_no>); ckeck->insert(n); } } } QueryResult TextQuery::query(const std::string& s) const { // 保存一个静态对象 如果未能找到单词,返回此对象 static std::shared_ptr<std::set<size_t>> nodata(new std::set<size_t>); auto location = wm.find(s); if (location == wm.end()) return QueryResult(s, words_file, nodata); else return QueryResult(s, words_file, location->second); } std::ostream& print(std::ostream& os, const QueryResult& qr){ os << qr.sought << " occurs " << qr.lines->size() << " " << (qr.lines->size() > 1 ? "times" : "time") << std::endl; for (auto num : *qr.lines) os << " (line " << num + 1 << ")" << *(qr.file->begin() + num) << std::endl; return os; }
将TextQuery的word_file成员和wm的值set都放在智能指针内,以便QueryResult类可以在正常访问。
TextQuery类:
TextqUuery的构造函数接受一个ifstream,用来读取文件,构造函数的初始化列表中,并且将word_file初始化为一个空的vector, getline从文件中读取一行存入string text中,首先将这一行的内容储存在word_file中,然后计算该行的行号,即就是word_file的大小size() - 1,istringstream对象用来读取string text中的每个单词,如果单词不在wm中,将这个单词对应的set申请一个新的内存空间, 然后将这个单词存入wm的string中,并将它所在的行号存入wm的set中,如果这个单词存在wm中,即使这个单词是第二次或第二次之后出现在同一行,lines->insert(n)并不会执行,因为set不允许重复关键字出现。
QueryResult类中,print函数将查找到的结果输出到屏幕。
QueryResult的构造函数接受一个string,一个shared_ptr,类型为set<size_t>, 还有一个shared_ptr,类型为vector<string>,参数string表示要查询的单词,sett的shared_ptr指向TextQuery的wm中的set,vector的shared_ptr指向TextQuery中的word_file。
TextQuerty中的query函数接受一个string,表示要查询的单词,在函数里声明了一个静态智能指针类型,用来表示未找到单词的set,表示没有该单词的行数可显示,然后在wm中查找该单词。
print函数用于打印给定的QueryResult对象:如果找到了单词,先打印这个单词和出现的次数,qr.lines->size();表示这个set的大小,即就是表示这个单词出现的次数;
然后在for循环中,num依次获取到这个单词出现的行数,由于我们习惯从1开始计数,因此将num + 1;然后在file中找到这一行的数据,*(qr.file->begin() + num), 从file这个vector的首元素开始向后便宜num个元素,即就是我们这个单词出现的那一行,然后我们解引用获得这给一行的string,并将它打印出来。