您的位置:首页 > 编程语言 > C语言/C++

《C++primer(第五版)》学习之路-第十二章:动态内存

2015-09-30 00:31 330 查看
【 声明:版权所有,转载请标明出处,请勿用于商业用途。 联系信箱:libin493073668@sina.com】

12.1 动态内存与智能指针

1.在C++中,动态内存的管理是通过一对运算符来完成:new,在动态内存中为对象分配空间并返回一个指向该对象的指针,我们可以选择对对象进行初始化;delete,接受一个动态对象的指针,销毁该对象,并释放与之关联的内存。

2.

shared_ptr允许多个指针指向同一个对象;unique_ptr则“独占”所指向的对象。标准库还定义了一个名为weak_ptr的伴随类,它是一种弱引用,指向shared_ptr所管理的对象。这三种类型都定义在memory头文件中。

3.

shared_ptr和unique_ptr都支持的操作

shared_ptr<T> sp

unique_ptr<T> up 空智能指针,可以指向类型为T的对象

p 将p用作一个条件判断,若p指向一个对象,则为true

*p 解引用p,获得它指向的对象

p->mem 等价于(*p).mem

p.get() 返回p中保存的指针。要小心使用,若智能指针释放了其对象,返回的指针所指向的对象也就消失了。

swap(p,q)

p.swap(q) 交换p和q中的指针

4.

shared_ptr独有的操作

make_shared<T>(args) 返回一个shared_ptr,指向一个动态分配的类型为T的对象。使用args初始化对象。

make_shared<T>p(q) p是shared_ptr q的拷贝;此操作会递增q中的计数器。q中的指针必须能转换为T*

p = q p和q都是shared_ptr,所保存的指针必须能相互转换。此操作会递减p的引用计数,递增q的引用计数;若p的引用计数变为0,则将其管理的原内存释放。

p.unique() 若p.use_count()为1,返回true;否则返回false

p.use_count() 返回与p共享对象的智能指针数量;可能很慢,主要用于测试

5.

由内置指针(而不是智能指针)管理的动态内存在被显式释放以前一直都会存在。

6.

定义和改变shared_ptr的其他方法

shared_ptr<T> p(q) p管理内置指针q所指向的对象;q必须指向new分配的内存,且能够转换为T*类型

shared_ptr<T> p(u) p从unique_ptr u那里接管了对象的所有权,将u置为空

shared_ptr<T> p(q,d) p接管了内置指针q所指向的对象的所有权。q必须能转换为T*类型。p将使用可调用对象d来代替delete

shared_ptr<T> p(p2,d) p是shared_ptr p2的拷贝,唯一的区别是p将用可调用对象d来代替delete

p.reset()

p.reset(q)

p.reset(q,d) 若p是唯一指向其对象的shared_ptr,reset会释放此对象。若传递了可选的参数内置指针q,会令p指向q,否则会将p置为空。若还传递了参数d,将会调用d而不是delete来释放q

7.

为了正确使用智能指针,我们必须坚持一些基本规范

⑴不使用相同的内置指针值初始化(或reset)多个智能指针

⑵不delete get()返回的指针

⑶不使用get()初始化或reset另一个智能指针

⑷如果你使用get()返回的指针,记住当最后一个对应的智能指针销毁后,你的指针就变成无效了

⑸如果你使用智能指针管理的资源不是new分配的内存,记住传递给它一个删除器

8.

unique_ptr操作

unique_ptr<T> u1

unique_ptr<T,p> u2 空unique_ptr,可以指向类型为T的对象。u1会使用delete来释放它的指针;u2会使用一个类型为D的可调用对象来释放它的指针

unique_ptr<T,p> u(d) 空unique_ptr,指向类型为T的对象,用类型为D的对象d代替delete

u = nullptr 释放u所指向的对象,将u置为空

u.release u放弃对指针的控制权,返回指针,并将u置为空

u.reset() 释放u指向的对象

u.reset(q)

u.reset(nullptr) 如果提供了内置指针q,令u指向这个对象;否则将u置为空

9.

weak_ptr操作

weak_ptr<T> w 空weak_ptr可以指向类型为T的对象

weak_ptr<T> w(sp) 与shared_ptr sp指向相同对象的weak_ptr。T必须能转换为sp指向的类型。

w = p p可以是一个shared_ptr或一个weak_ptr。赋值后w与p共享对象

w.reset() 将w置为空

w.use_count() 与w共享对象的shared_ptr的数量

w.expired() 若w.use_count()为0,返回true,否则返回false

w.lock() 如果expired为true,返回一个空shared_ptr;否则返回一个指向w的对象的shared_ptr

12.2 动态数组

1.动态数组并不是数组类型,而是得到一个数组元素类型的指针。

2.

指向数组的unique_ptr

指向数组的unique_ptr不支持成员访问运算符

其他unique_ptr操作不变

unique_ptr<T[]> u u可以指向一个动态分配的数组,数组元素类型为T

unique_ptr<T[]> u(p) u指向内置指针p所指向的动态分配的数组。p必须能转换为类型T*

u[i] 返回u拥有的数组中位置i处的对象,u必须指向一个数组

3.标准库allocator类定义在头文件memory中,它帮助我们将内存分配和对象构造分离开来。它提供一种类型感知的内存分配方法,它分配的内存是原始的,未构造的。

4.

标准库allocator类及其算法

allocator<T> a 定义了一个名为a的allocator对象,它可以为类型为T的对象分配内存

a.allocator(n) 分配一段原始的,未构造的内存,保存n个类型为T的对象

a.deallocate(p,n) 释放从T*指针p中地址开始的内存,这块内存保存了n个类型为T的对象;p必须是一个先前由allocate返回的指针,且n必须是p创建时所要求的大小。在调用deallocate之前,用户必须对每个在这块内存中创建的对象调用destory。

a.construct(p,args) p必须是一个类型为T*的指针,指向一块原始内存;arg被传递给类型为T的构造函数,用来在p指向的内存中构造一个对象

a.destroy(p) p为T*类型的指针,此算法对p指向的对象指向析构函数

5.

allocator算法

这些函数在给定目的位置创建元素,而不是由系统分配内存给它们。

uninitialized_copy(b,e,b2) 从迭代器b和e指出的输入范围中拷贝元素到迭代器b2指定的未构造的原始内存中。b2指向的内存必须足够大,能容纳输入序列中元素的拷贝

uninitialized_copy_n(b,n,b2)
从迭代器b指向的元素开始,拷贝n个元素到b2开始的内存中

uninitialized_fill(b,e,t)
在迭代器b和e指定的原始内存范围中创建对象,对象的值均为t的拷贝

uninitialized_fill_n(b,n,t)
从迭代器b指向的内存地址开始创建n个对象。b必须指向足够大的未构造的原始内存,能够容纳给定数量的对象

PS:部分练习答案

练习12.1

b2被销毁,但是b2里面的元素不会被销毁,所以b1,b2都有4个元素

练习12.2

ex12_02.h

#include <vector>
#include <string>
#include <initializer_list>
#include <memory>
#include <exception>

using std::vector;
using std::string;

class StrBlob
{
public:
using size_type = vector<string>::size_type;

StrBlob():data(std::make_shared<vector<string>>()) {}
StrBlob(std::initializer_list<string> il):data(std::make_shared<vector<string>>(il)) {}

size_type size() const
{
return data->size();
}
bool empty() const
{
return data->empty();
}

void push_back(const string& t)
{
data->push_back(t);
}
void pop_back()
{
check(0,"pop_back on empty StrBlob");
data->pop_back();
}

std::string& front()
{
check(0,"front on empty StrBlob");
return data->front();
}

std::string& back()
{
check(0,"back on empty StrBlob");
return data->back();
}

const std::string& front() const
{
check(0,"front on empty StrBlob");
return data->front();
}

const std::string& back() const
{
check(0,"back on empty StrBlob");
return data->back();
}

private:
void check(size_type i,const string& msg) const
{
if(i>=data->size())
throw std::out_of_range(msg);
}
private:
std::shared_ptr<vector<string>> data;
};


text.cpp

#include <iostream>
#include "ex12_02.h"

int main()
{
const StrBlob csb{"one","two","three"};
StrBlob sb{"one","two","four"};

std::cout << csb.front() << " " << csb.back() << std::endl;
sb.back() = "three";
std::cout << sb.front() << " " << sb.back() << std::endl;
}


练习12.6

#include <iostream>
#include <vector>
#include <string>
#include <memory>

std::vector<int>* dynamic_vector_generator()
{
std::vector<int>* ptr_v = new std::vector<int>();
return ptr_v;
}

void dynamic_vector_processor(std::vector<int>* ptr_v)
{
int i;
std::cout << "please enter:" << std::endl;
while(std::cin >> i && i!=999)
ptr_v->push_back(i);
}

void dynamic_vector_printer(std::vector<int>* ptr_v)
{
for(const auto& elem: *ptr_v)
std::cout << elem << " ";
std::cout << std::endl;
}

int main()
{
std::vector<int>* ptr_vi = dynamic_vector_generator();
dynamic_vector_processor(ptr_vi);
dynamic_vector_printer(ptr_vi);
delete ptr_vi;
return 0;
}


练习12.7

#include <iostream>
#include <vector>
#include <string>
#include <memory>

std::shared_ptr<std::vector<int>> dynamic_vector_generator_sptr()
{
return std::make_shared<std::vector<int>>();
}

void dynamic_vector_processor_sptr(std::shared_ptr<std::vector<int>> sptr_vi)
{
int i;
std::cout << "please enter:" << std::endl;
while(std::cin >> i && i!=999)
sptr_vi->push_back(i);
}

void dynamic_vector_printer_sptr(const std::shared_ptr<std::vector<int>> sptr_vi)
{
for(const auto& elem: *sptr_vi)
std::cout << elem << " ";
std::cout << std::endl;
}

int main()
{
auto sptr = dynamic_vector_generator_sptr();
dynamic_vector_processor_sptr(sptr);
dynamic_vector_printer_sptr(sptr);
return 0;
}


练习12.14

#include <iostream>
#include <string>
#include <memory>

struct connection
{
std::string ip;
int port;
connection(std::string ip_,int port_):ip(ip_),port(port_){}
};

struct destination
{
std::string ip;
int port;
destination(std::string ip_,int port_):ip(ip_),port(port_){}
};

connection connect(destination* pDest)
{
std::shared_ptr<connection> pConn(new connection(pDest->ip,pDest->port));
std::cout << "creating connection(" << pConn.use_count() << ")" << std::endl;
return *pConn;
}

void disconnect(connection pConn)
{
std::cout << "connection close(" << pConn.ip << ":" << pConn.port << ")" << std::endl;
}

void end_connection(connection* pConn)
{
disconnect(*pConn);
}

void f(destination& d)
{
connection conn = connect(&d);
std::shared_ptr<connection> p(&conn,end_connection);
std::cout << "connection now(" << p.use_count() << ")" << std::endl;
}

int main()
{
destination dest("202.118.176.67",3316);
f(dest);

return 0;
}


练习12.15

#include <iostream>
#include <string>
#include <memory>

struct connection
{
std::string ip;
int port;
connection(std::string ip_,int port_):ip(ip_),port(port_){}
};

struct destination
{
std::string ip;
int port;
destination(std::string ip_,int port_):ip(ip_),port(port_){}
};

connection connect(destination* pDest)
{
std::shared_ptr<connection> pConn(new connection(pDest->ip,pDest->port));
std::cout << "creating connection(" << pConn.use_count() << ")" << std::endl;
return *pConn;
}

void disconnect(connection pConn)
{
std::cout << "connection close(" << pConn.ip << ":" << pConn.port << ")" << std::endl;
}

void f(destination& d)
{
connection conn = connect(&d);
std::shared_ptr<connection> p(&conn,[](connection* pConn){disconnect(*pConn);});
std::cout << "connection now(" << p.use_count() << ")" << std::endl;
}

int main()
{
destination dest("202.118.176.67",3316);
f(dest);

return 0;
}


练习12.19

ex12_19.h

#ifndef CP5_ex12_19_h
#define CP5_ex12_19_h

#include <vector>
#include <string>
#include <initializer_list>
#include <memory>
#include <exception>

using std::vector;
using std::string;

class StrBlobPtr;

class StrBlob
{
public:
using size_type = vector<string>::size_type;
friend class StrBlobPtr;

StrBlobPtr begin();
StrBlobPtr end();

StrBlob():data(std::make_shared<vector<string>>()) {}
StrBlob(std::initializer_list<string> il):data(std::make_shared<vector<string>>(il)){}

size_type size() const
{
return data->size();
}
bool empty() const
{
return data->empty();
}

void push_back(const string& t)
{
data->push_back(t);
}

void pop_back()
{
check(0,"pop_back on empty StrBlob");
data->pop_back();
}

std::string& back()
{
check(0, "back on empty StrBlob");
return data->back();
}

const std::string& front() const
{
check(0, "front on empty StrBlob");
return data->front();
}
const std::string& back() const
{
check(0, "back on empty StrBlob");
return data->back();
}

private:
void check(size_type i,const string& msg) const
{
if(i>=data->size())
throw std::out_of_range(msg);
}

private:
std::shared_ptr<vector<string>> data;
};

class StrBlobPtr
{
public:
StrBlobPtr():curr(0){}
StrBlobPtr(StrBlob& a,size_t sz = 0):wptr(a.data),curr(sz){}
bool operator!=(const StrBlobPtr& p)
{
return p.curr!=curr;
}
string& deref()const
{
auto p = check(curr,"dereference past end");
return (*p)[curr];
}
StrBlobPtr& incr()
{
check(curr,"increament past end of StrBlobPtr");
++curr;
return *this;
}

private:
std::shared_ptr<vector<string>> check(size_t i,const string& msg) const
{
auto ret = wptr.lock();
if(!ret)
throw std::runtime_error("unbound StrBlobPtr");
if(i>=ret->size())
throw std::out_of_range(msg);
return ret;
}

std::weak_ptr<vector<string>> wptr;
size_t curr;
};

#endif


ex12_19.cpp

#include "ex12_19.h"

StrBlobPtr StrBlob::begin()
{
return StrBlobPtr(*this);
}

StrBlobPtr StrBlob::end()
{
return StrBlobPtr(*this,data->size());
}


练习12.20

#include "ex12_19.h"
#include <fstream>
#include <iostream>

int main()
{
std::ifstream ifs("book.txt");
StrBlob blob;
for(std::string str; std::getline(ifs,str);)
blob.push_back(str);
for(StrBlobPtr pbeg(blob.begin()),pend(blob.end()); pbeg!=pend; pbeg.incr())
std::cout<<pbeg.deref()<<std::endl;
}


练习12.22

ex12_22.h

#ifndef CP5_ex12_22_h
#define CP5_ex12_22_h

#include <vector>
#include <string>
#include <initializer_list>
#include <memory>
#include <exception>

using std::vector;
using std::string;

class ConstStrBlobPtr;

class StrBlob
{
public:
using size_type = vector<string>::size_type;
friend class ConstStrBlobPtr;

StrBlobPtr begin() const;
StrBlobPtr end() const;

StrBlob():data(std::make_shared<vector<string>>()) {}
StrBlob(std::initializer_list<string> il):data(std::make_shared<vector<string>>(il)) {}

size_type size() const
{
return data->size();
}
bool empty() const
{
return data->empty();
}

void push_back(const string& t)
{
data->push_back(t);
}

void pop_back()
{
check(0,"pop_back on empty StrBlob");
data->pop_back();
}

std::string& back()
{
check(0, "back on empty StrBlob");
return data->back();
}

const std::string& front() const
{
check(0, "front on empty StrBlob");
return data->front();
}
const std::string& back() const
{
check(0, "back on empty StrBlob");
return data->back();
}

private:
void check(size_type i,const string& msg) const
{
if(i>=data->size())
throw std::out_of_range(msg);
}

private:
std::shared_ptr<vector<string>> data;
};

class ConstStrBlobPtr
{
public:
ConstStrBlobPtr():curr(0) {}
ConstStrBlobPtr(const StrBlob& a,size_t sz = 0):wptr(a.data),curr(sz) {}
bool operator!=(ConstStrBlobPtr& p)
{
return p.curr!=curr;
}
const string& deref()const
{
auto p = check(curr,"dereference past end");
return (*p)[curr];
}
ConstStrBlobPtr& incr()
{
check(curr,"increament past end of StrBlobPtr");
++curr;
return *this;
}

private:
std::shared_ptr<vector<string>> check(size_t i,const string& msg) const
{
auto ret = wptr.lock();
if(!ret)
throw std::runtime_error("unbound StrBlobPtr");
if(i>=ret->size())
throw std::out_of_range(msg);
return ret;
}

std::weak_ptr<vector<string>> wptr;
size_t curr;
};

#endif


ex12_22.cpp

#include "ex12_19.h"

ConstStrBlobPtr StrBlob::begin() const
{
return ConstStrBlobPtr(*this);
}

ConstStrBlobPtr StrBlob::end() const
{
return ConstStrBlobPtr(*this,data->size());
}


练习12.23

#include <iostream>
#include <string>
#include <cstring>

int main()
{
char *concatenate_string = new char[255]();
strcat(concatenate_string,"hello ");
strcat(concatenate_string,"world");
std::cout << concatenate_string << std::endl;
delete[] concatenate_string;

std::string str1{"hello "},str2{"world"};
std::cout << str1+str2 << std::endl;
}


练习12.24

#include <iostream>

int main()
{
std::cout << "How long do you want the string? ";
int size {0};
std::cin >> size;
char* input = new char[size + 1]();
std::cin.ignore();
std::cout << "input the string: ";
std::cin.get(input, size + 1);
std::cout << input;
delete[] input;
}


练习12.26

#include <iostream>
#include <string>
#include <memory>

void input_reverse_output_string(int n)
{
std::allocator<std::string> alloc;
auto const p = alloc.allocate(n);
std::string s;
auto q = p;
while(std::cin >> s && q!=p+n) alloc.construct(q++,s);
while(q!=p)
{
std::cout << *--q << " ";
alloc.destroy(q);
}
alloc.deallocate(p,n);
}

int main()
{
input_reverse_output_string(5);
return 0;
}


练习12.27 & 12.30

ex12_27_30.h

#ifndef CP5_ex12_27_h
#define CP5_ex12_27_h

#include <string>
using std::string;

#include <vector>
using std::vector;

#include <memory>
using std::shared_ptr;

#include <iostream>
#include <fstream>
#include <map>
#include <set>

class QueryResult;
class TextQuery
{
public:
using LineNo = vector<string>::size_type;
TextQuery(std::ifstream&);
QueryResult query(const string&) const;

private:
shared_ptr<vector<string>> input;
std::map<string, shared_ptr<std::set<LineNo>>> result;
};

class QueryResult
{
public:
friend std::ostream& print(std::ostream&, const QueryResult&);

public:
QueryResult(const string& s, shared_ptr<std::set<TextQuery::LineNo>> set,
shared_ptr<vector<string>> v)
: word(s), nos(set), input(v)
{
}

private:
string word;
shared_ptr<std::set<TextQuery::LineNo>> nos;
shared_ptr<vector<string>> input;
};

std::ostream& print(std::ostream&, const QueryResult&);

#endif


ex12_27_30.cpp

#include "ex12_27_30.h"
#include <sstream>
#include <algorithm>

TextQuery::TextQuery(std::ifstream& ifs) : input(new vector<string>)
{
LineNo lineNo {0};
for (string line; std::getline(ifs, line); ++lineNo)
{
input->push_back(line);
std::istringstream line_stream(line);
for (string text, word; line_stream >> text; word.clear())
{
std::remove_copy_if(text.begin(), text.end(),
std::back_inserter(word), ispunct);
auto& nos = result[word];
if (!nos) nos.reset(new std::set<LineNo>);
nos->insert(lineNo);
}
}
}

QueryResult TextQuery::query(const string& str) const
{
static shared_ptr<std::set<LineNo>> nodate(new std::set<LineNo>);
auto found = result.find(str);
if (found == result.end())
return QueryResult(str, nodate, input);
else
return QueryResult(str, found->second, input);
}

std::ostream& print(std::ostream& out, const QueryResult& qr)
{
out << qr.word << " occurs " << qr.nos->size()
<< (qr.nos->size() > 1 ? " times" : " time") << std::endl;
for (auto i : *qr.nos)
out << "\t(line " << i + 1 << ") " << qr.input->at(i) << std::endl;
return out;
}


text.cpp

#include "ex12_27_30.h"
#include <iostream>

void runQueries(std::ifstream& infile)
{
TextQuery tq(infile);
while (true)
{
std::cout << "enter word to look for, or q to quit: ";
string s;
if (!(std::cin >> s) || s == "q") break;
print(std::cout, tq.query(s)) << std::endl;
}
}

int main()
{
std::ifstream file("<span style="color: rgb(24, 54, 145); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; line-height: 16px; white-space: pre;">storyDataFile</span>.txt");
runQueries(file);
}


练习12.28

#include <string>
#include <vector>
#include <memory>
#include <iostream>
#include <fstream>
#include <sstream>
#include <map>
#include <set>
#include <algorithm>

using std::string;
using std::vector;
using std::shared_ptr;

int main()
{
std::ifstream file("letter.txt");
vector<string> input;
std::map<string, std::set<decltype(input.size())>> dictionary;
decltype(input.size()) lineNo {0};

for (string line; std::getline(file, line); ++lineNo)
{
input.push_back(line);
std::istringstream line_stream(line);
for (string text, word; line_stream >> text; word.clear())
{
std::remove_copy_if(text.begin(), text.end(),
std::back_inserter(word), ispunct);
dictionary[word].insert(lineNo);
}
}

while (true)
{
std::cout << "enter word to look for, or q to quit: ";
string s;
if (!(std::cin >> s) || s == "q") break;
auto found = dictionary.find(s);
if (found != dictionary.end())
{
std::cout << s << " occurs " << found->second.size()
<< (found->second.size() > 1 ? " times" : " time")
<< std::endl;
for (auto i : found->second)
std::cout << "\t(line " << i + 1 << ") " << input.at(i)
<< std::endl;
}
else
std::cout << s << " occurs 0 time" << std::endl;
}
}


练习12.32

ex12_32.h

#ifndef CP5_ex12_32_h
#define CP5_ex12_32_h

#include "ex12_22.h"
using std::shared_ptr;

#include <iostream>
#include <fstream>
#include <map>
#include <set>

class QueryResult;
class TextQuery
{
public:
TextQuery(std::ifstream&);
QueryResult query(const string&) const;

private:
shared_ptr<StrBlob> input;
std::map<string, shared_ptr<std::set<StrBlob::size_type>>> result;
};

class QueryResult
{
public:
friend std::ostream& print(std::ostream&, const QueryResult&);

public:
QueryResult(const string& s, shared_ptr<std::set<StrBlob::size_type>> set,
shared_ptr<StrBlob> v)
: word(s), nos(set), input(v)
{
}

private:
string word;
shared_ptr<std::set<StrBlob::size_type>> nos;
shared_ptr<StrBlob> input;
};

std::ostream& print(std::ostream&, const QueryResult&);

#endif


ex12_32.cpp

#include "ex12_32.h"
#include <sstream>
#include <algorithm>

TextQuery::TextQuery(std::ifstream& ifs) : input(new StrBlob)
{
StrBlob::size_type lineNo {0};
for (string line; std::getline(ifs, line); ++lineNo)
{
input->push_back(line);
std::istringstream line_stream(line);
for (string text, word; line_stream >> text; word.clear())
{
std::remove_copy_if(text.begin(), text.end(),
std::back_inserter(word), ispunct);
auto& nos = result[word];
if (!nos) nos.reset(new std::set<StrBlob::size_type>);
nos->insert(lineNo);
}
}
}

QueryResult TextQuery::query(const string& str) const
{
static shared_ptr<std::set<StrBlob::size_type>> nodate(
new std::set<StrBlob::size_type>);
auto found = result.find(str);
if (found == result.end())
return QueryResult(str, nodate, input);
else
return QueryResult(str, found->second, input);
}

std::ostream& print(std::ostream& out, const QueryResult& qr)
{
out << qr.word << " occurs " << qr.nos->size()
<< (qr.nos->size() > 1 ? " times" : " time") << std::endl;
for (auto i : *qr.nos)
{
ConstStrBlobPtr p(*qr.input, i);
out << "\t(line " << i + 1 << ") " << p.deref() << std::endl;
}
return out;
}


练习12.33

ex12_33.h

#ifndef CP5_ex12_33_h
#define CP5_ex12_33_h

#include "ex12_22.h"
using std::shared_ptr;

#include <iostream>
#include <fstream>
#include <map>
#include <set>

class QueryResult;
class TextQuery
{
public:
TextQuery(std::ifstream&);
QueryResult query(const string&) const;

private:
shared_ptr<StrBlob> input;
std::map<string, shared_ptr<std::set<StrBlob::size_type>>> result;
};

class QueryResult
{
public:
using ResultIter = std::set<StrBlob::size_type>::iterator;
friend std::ostream& print(std::ostream&, const QueryResult&);

public:
QueryResult(const string& s, shared_ptr<std::set<StrBlob::size_type>> set,
shared_ptr<StrBlob> v)
: word(s), nos(set), input(v)
{
}
ResultIter begin() const
{
return nos->begin();
}
ResultIter end() const
{
return nos->end();
}
shared_ptr<StrBlob> get_file() const
{
return input;
}
private:
string word;
shared_ptr<std::set<StrBlob::size_type>> nos;
shared_ptr<StrBlob> input;
};

std::ostream& print(std::ostream&, const QueryResult&);

#endif


ex12_33.cpp

#include "ex12_33.h"
#include <sstream>
#include <algorithm>

TextQuery::TextQuery(std::ifstream& ifs) : input(new StrBlob)
{
StrBlob::size_type lineNo {0};
for (string line; std::getline(ifs, line); ++lineNo)
{
input->push_back(line);
std::istringstream line_stream(line);
for (string text, word; line_stream >> text; word.clear())
{
std::remove_copy_if(text.begin(), text.end(),
std::back_inserter(word), ispunct);
auto& nos = result[word];
if (!nos) nos.reset(new std::set<StrBlob::size_type>);
nos->insert(lineNo);
}
}
}

QueryResult TextQuery::query(const string& str) const
{
static shared_ptr<std::set<StrBlob::size_type>> nodate(
new std::set<StrBlob::size_type>);
auto found = result.find(str);
if (found == result.end())
return QueryResult(str, nodate, input);
else
return QueryResult(str, found->second, input);
}

std::ostream& print(std::ostream& out, const QueryResult& qr)
{
out << qr.word << " occurs " << qr.nos->size()
<< (qr.nos->size() > 1 ? " times" : " time") << std::endl;
for (auto it = qr.begin(); it != qr.end(); ++it)
{
ConstStrBlobPtr p(*qr.get_file(), *it);
out << "\t(line " << *it + 1 << ") " << p.deref() << std::endl;
}
return out;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++primer