C++ Primer: Chapter 12 Dynamic Memory

strblob类

strblob.h中:

#include<initializer_list>
#include<string>
#include<memory>
#include<vector>
using namespace std;

class strblobptr; //先声明类
class conststrblobptr; 

class strblob
{
	friend class strblobptr;
	friend class conststrblobptr;
public:

	typedef vector<string>::size_type size_type;
	strblob() : data(make_shared<vector<string>>()) {};
	strblob(initializer_list<string> il) : data(make_shared<vector<string>>(il)) {}; //可传入任意大小的string链表
	size_type size() const { return data->size(); } //函数体调用的size()是vector的size()成员函数
	bool empty() const { return data->empty(); }
	//添加和删除元素
	void push_back(const string& t) { data->push_back(t); };
	void pop_back();
	//元素访问
	string& front();
	const string& front() const;
	string& back();
	const string& back() const;
	//迭代器操作
	strblobptr begin();
	strblobptr end();

private:
	//strblob类的底层是一个vector<string>
	shared_ptr<vector<string>> data;
	//如果data[i]不合法,抛出一个异常
	void check(size_type i, const string& msg) const;
};

class strblobptr
{
	friend bool eq(const strblobptr& lhs, const strblobptr& rhs);
	friend bool neq(const strblobptr& lhs, const strblobptr& rhs);
public:
	strblobptr() : curr(0) {};
	strblobptr(strblob& a, size_t sz = 0) : wptr(a.data), curr(sz) {};
	string& deref() const; //访问指针所指元素
	strblobptr& incr(); //递增指针

private:
	shared_ptr<vector<string>> check(size_t, const string&) const;
	weak_ptr<vector<string>> wptr;
	size_t curr;
};

bool eq(const strblobptr& lhs, const strblobptr& rhs);
bool neq(const strblobptr& lhs, const strblobptr& rhs);

class conststrblobptr
{
public:
	conststrblobptr() : curr(0) {};
	conststrblobptr(const strblob& a, size_t sz = 0) : wptr(a.data), curr(sz) {};
	string& deref() const; //访问指针所指元素
	conststrblobptr& incr(); //递增指针

private:
	shared_ptr<vector<string>> check(size_t, const string&) const;
	weak_ptr<vector<string>> wptr;
	size_t curr;
};

strblob.cpp中:

#include "strblob.h"
#include<stdexcept>

//===== strblob =====

void strblob::check(size_type i, const string& msg) const
{
	if (i >= data->size())
		throw out_of_range(msg); //throw索引越界的异常
}

//访问元素
string& strblob::front()
{
	check(0, "front on empty strblob");
	return data->front(); //调用底层vector的front()方法作为返回值
}
const string& strblob::front() const
{
	check(0, "front on empty strblob");
	return data->front(); 
}
string& strblob::back()
{
	check(0, "front on empty strblob");
	return data->back();
}
const string& strblob::back() const
{
	check(0, "front on empty strblob");
	return data->back();
}
//删除元素
void strblob::pop_back()
{
	check(0, "pop_back on empty strblob");
	return data->pop_back();
}

//迭代器操作
strblobptr strblob::begin() 
{ 
	return strblobptr(*this); 
}

strblobptr strblob::end() 
{ 
	auto ret = strblobptr(*this, data->size()); 
	return ret; 
}

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

string& strblobptr::deref() const
{
	auto p = check(curr, "dereference past end");
	return (*p)[curr];
}

strblobptr& strblobptr::incr()
{
	check(curr, "increment past end of strblobptr");
	++curr;
	return *this;
}

// StrBlobPtr 的比较操作
bool eq(const strblobptr& lhs, const strblobptr& rhs) {
	auto l = lhs.wptr.lock(), r = rhs.wptr.lock();
	// 若底层的 vector 是同一个
	if (l == r)
		// 则两个指针都是空,或者指向相同元素时,它们相等
		return (!r || lhs.curr == rhs.curr);
	else
		return false;       // 若指向不同 vector,则不可能相等
}

bool neq(const strblobptr& lhs, const strblobptr& rhs) {
	return !eq(lhs, rhs);
}

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

string& conststrblobptr::deref() const
{
	auto p = check(curr, "dereference past end");
	return (*p)[curr];
}

conststrblobptr& conststrblobptr::incr()
{
	check(curr, "increment past end of strblobptr");
	++curr;
	return *this;
}

TextQuery类

TextQuery.h

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

using namespace std;

class QueryResult;

class TextQuery
{
	friend class QueryResult;
public:
	using line_no = vector<string>::size_type;
	TextQuery(ifstream&) : file(new vector<string>) {};
	QueryResult query(const string& word) const;

private:
	shared_ptr<vector<string>> file;
	map<string, shared_ptr<set<line_no>>> wm;
};

class QueryResult
{
	friend ostream& print(ostream&, const QueryResult&);
public:
	using line_no = vector<string>::size_type;
	using line_it = set<line_no>::const_iterator;
	QueryResult(string s, shared_ptr<set<line_no>> p, shared_ptr<vector<string>> f) : sought(s), lines(p), file(f) {};
	line_it begin() const { lines->begin(); };
	line_it end() const { lines->end(); };
	shared_ptr<vector<string>> get_file() { return file; };
private:
	string sought;
	shared_ptr<set<line_no>> lines;
	shared_ptr<vector<string>> file;
};

TextQuery.cpp

#include"TextQuery.h"
#include<sstream>
#include<algorithm>
#include<iostream>

TextQuery::TextQuery(ifstream& is) : file(new vector<string>) 
{
	string text;
	while (getline(is, text))
	{
		file->push_back(text);
		int n = file->size() - 1;
		istringstream line(text);
		string word;
		while (line >> word)
		{
			shared_ptr<set<line_no>>& lines = wm[word]; //lines是指向set的智能指针
			if (!lines) //第一次遇到word时需要给lines分配一个新的内存空间
				lines.reset(new set<line_no>); 
			lines->insert(n);
		}
	}
}

QueryResult TextQuery::query(const string& sought) const
{
	static shared_ptr<set<line_no>> nodata(new set<line_no>);
	auto loc = wm.find(sought);
	if (loc == wm.end())
		return QueryResult(sought, nodata, file); //未找到
	else
		return QueryResult(sought, loc->second, file);
}

ostream& print(ostream& os, const QueryResult& qr)
{
	os << qr.sought << " occurs " << qr.lines->size() << " " << ((qr.lines->size()) > 1 ? "times" : "time") << endl;
	for (auto num : *qr.lines)
		os << "\t(line " << num + 1 << ") " << *(qr.file->begin() + num) << endl;
	return os;
}

Homework

Test 12.2

#include<vector>
#include<string>
#include<memory>
#include<initializer_list>
using std::vector, std::string, std::initializer_list, std::shared_ptr, std::make_shared;

class strblob
{
public:
	typedef vector<string>::size_type size_type;
	strblob() : data(make_shared<vector<string>>()) {};
	strblob(initializer_list<string> il) : data(make_shared<vector<string>>(il)) {}; //可传入任意大小的string链表
	size_type size() const { return data->size(); } //函数体调用的size()是vector的size()成员函数
	bool empty() const { return data->empty(); }
	//添加和删除元素
	void push_back(const string& t) { data->push_back(t); };
	void pop_back();
	//元素访问
	string& front();
	const string& front() const;
	string& back();
	const string& back() const;

private:
	//strblob类的底层是一个vector<string>
	shared_ptr<vector<string>> data;
	//如果data[i]不合法,抛出一个异常
	void check(size_type i, const string& msg) const;
};
#include "strblob.h"
#include<stdexcept>

using std::out_of_range;

void strblob::check(size_type i, const string& msg) const
{
	if (i >= data->size())
		throw out_of_range(msg); //throw索引越界的异常
}

//访问元素
string& strblob::front()
{
	check(0, "front on empty strblob");
	return data->front(); //调用底层vector的front()方法作为返回值
}
const string& strblob::front() const
{
	check(0, "front on empty strblob");
	return data->front(); 
}
string& strblob::back()
{
	check(0, "front on empty strblob");
	return data->back();
}
const string& strblob::back() const
{
	check(0, "front on empty strblob");
	return data->back();
}
//删除元素
void strblob::pop_back()
{
	check(0, "pop_back on empty strblob");
	return data->pop_back();
}

Test 12.5

explicit阻止了参数传递时的隐式类型转换,这意味着我们不能直接用{"s1", "s2"}类似的列表作为形参传递给构造函数。通常来说,使用隐式类型转换可以让程序写起来更加简单方便给。

但这种隐式转换并不总是好的。例如,列表中可能并非都是合法的值。再如,对于接受 strblob的函数,传递给它一个列表,会创建一个临时的 strblob 对象,用列表对其初始化,然后将其传递给函数,当函数完成后,此对象将被丢弃,再也无法访问了。对于这些情况,我们可以定义显式的构造函数,禁止隐式类类型转换。

Test 12.6

vector<int>* func()
{
	return new vector<int>({ 1, 2, 3, 4 , 5 });
}

vector<int> save(vector<int>* vp)
{
	vector<int> ivec = *vp;
	delete vp;
	return ivec;
}

void print(const vector<int>& ivec)
{
	for (auto& i : ivec)
		cout << i << " ";
}

int main()
{
	print(save(func()));

	return 0;
}

Test 12.7

shared_ptr<vector<int>> func()
{
	return make_shared<vector<int>>(10, 1);
}

vector<int> save(shared_ptr<vector<int>> sp)
{
	return *sp;
}

void print(const vector<int>& ivec)
{
	for (auto& i : ivec)
		cout << i << " ";
}

int main()
{
	print(save(func()));

	return 0;
}

Test 12.8

从程序片段看,可以猜测程序员的意图是通过 new 返回的指针值来区分内存分配成功或失败 —— 成功返回一个合法指针,转换为整型是一个非零值,可转换为 bool 值 true;分配失败,p 得到 nullptr,其整型值是 0,可转换为 bool 值 false。

但普通 new 调用在分配失败时抛出一个异常 bad_alloc,而不是返回 nullptr,因此程序不能达到预想的目的。

可将 new int 改为 new (nothrow) int 来令 new 在分配失败时不抛出异常,而是返回 nullptr。但这仍然不是一个好方法,应该通过捕获异常或是判断返回的指针来返回 true 或 false,而不是依赖类型转换。

Test 12.10

此调用是正确的,利用 p 创建一个临时的 shared_ptr 赋予 process 的参数 ptr,p 和 ptr 都指向相同的 int 对象,引用计数被正确地置为 2。process 执行完毕后,ptr 被销毁,int 对象 42 引用计数减 1,这是正确的 —— 只有 p 指向它。

Test 12.14

struct connection
{

};
struct destination;
connection connect(destination*);
void disconnect(connection);
void end_connection(connection* p) { disconnect(*p); }
void f(destination& d)
{
	connection c = connect(&d);
	shared_ptr<connection> p(&c, end_connection);
	//....
}

Test 12.15

struct connection
{

};
struct destination;
connection connect(destination*);
void disconnect(connection);
void f(destination& d)
{
	connection c = connect(&d);
	shared_ptr<connection> p(&c, [](connection *p) {disconnect(*p);});
	//....
	
}

Test 12.19

strblob.h

#include<initializer_list>
#include<string>
#include<memory>
#include<vector>
using namespace std;

class strblobptr; //先声明类

class strblob
{
	friend class strblobptr;
public:

	typedef vector<string>::size_type size_type;
	strblob() : data(make_shared<vector<string>>()) {};
	strblob(initializer_list<string> il) : data(make_shared<vector<string>>(il)) {}; //可传入任意大小的string链表
	size_type size() const { return data->size(); } //函数体调用的size()是vector的size()成员函数
	bool empty() const { return data->empty(); }
	//添加和删除元素
	void push_back(const string& t) { data->push_back(t); };
	void pop_back();
	//元素访问
	string& front();
	const string& front() const;
	string& back();
	const string& back() const;
	//迭代器操作
	strblobptr begin();
	strblobptr end();

private:
	//strblob类的底层是一个vector<string>
	shared_ptr<vector<string>> data;
	//如果data[i]不合法,抛出一个异常
	void check(size_type i, const string& msg) const;
};

class strblobptr
{
public:
	strblobptr() : curr(0) {};
	strblobptr(strblob& a, size_t sz = 0) : wptr(a.data), curr(sz) {};
	string& deref() const; //访问指针所指元素
	strblobptr& incr(); //递增指针

private:
	shared_ptr<vector<string>> check(size_t, const string&) const;
	weak_ptr<vector<string>> wptr;
	size_t curr;
};

strblob.cpp

#include "strblob.h"
#include<stdexcept>

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

string& strblobptr::deref() const
{
	auto p = check(curr, "dereference past end");
	return (*p)[curr];
}

strblobptr& strblobptr::incr()
{
	check(curr, "increment past end of strblobptr");
	++curr;
	return *this;
}


void strblob::check(size_type i, const string& msg) const
{
	if (i >= data->size())
		throw out_of_range(msg); //throw索引越界的异常
}

//访问元素
string& strblob::front()
{
	check(0, "front on empty strblob");
	return data->front(); //调用底层vector的front()方法作为返回值
}
const string& strblob::front() const
{
	check(0, "front on empty strblob");
	return data->front(); 
}
string& strblob::back()
{
	check(0, "front on empty strblob");
	return data->back();
}
const string& strblob::back() const
{
	check(0, "front on empty strblob");
	return data->back();
}
//删除元素
void strblob::pop_back()
{
	check(0, "pop_back on empty strblob");
	return data->pop_back();
}

//迭代器操作
strblobptr strblob::begin() 
{ 
	return strblobptr(*this); 
}

strblobptr strblob::end() 
{ 
	auto ret = strblobptr(*this, data->size()); 
	return ret; 
}

Test 12.20

strblob.h

#include<initializer_list>
#include<string>
#include<memory>
#include<vector>
using namespace std;

class strblobptr; //先声明类

class strblob
{
	friend class strblobptr;
public:

	typedef vector<string>::size_type size_type;
	strblob() : data(make_shared<vector<string>>()) {};
	strblob(initializer_list<string> il) : data(make_shared<vector<string>>(il)) {}; //可传入任意大小的string链表
	size_type size() const { return data->size(); } //函数体调用的size()是vector的size()成员函数
	bool empty() const { return data->empty(); }
	//添加和删除元素
	void push_back(const string& t) { data->push_back(t); };
	void pop_back();
	//元素访问
	string& front();
	const string& front() const;
	string& back();
	const string& back() const;
	//迭代器操作
	strblobptr begin();
	strblobptr end();

private:
	//strblob类的底层是一个vector<string>
	shared_ptr<vector<string>> data;
	//如果data[i]不合法,抛出一个异常
	void check(size_type i, const string& msg) const;
};

class strblobptr
{
	friend bool eq(const strblobptr& lhs, const strblobptr& rhs);
	friend bool neq(const strblobptr& lhs, const strblobptr& rhs);
public:
	strblobptr() : curr(0) {};
	strblobptr(strblob& a, size_t sz = 0) : wptr(a.data), curr(sz) {};
	string& deref() const; //访问指针所指元素
	strblobptr& incr(); //递增指针

private:
	shared_ptr<vector<string>> check(size_t, const string&) const;
	weak_ptr<vector<string>> wptr;
	size_t curr;
};

bool eq(const strblobptr& lhs, const strblobptr& rhs);
bool neq(const strblobptr& lhs, const strblobptr& rhs);

strblob.cpp

#include "strblob.h"
#include<stdexcept>

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

string& strblobptr::deref() const
{
	auto p = check(curr, "dereference past end");
	return (*p)[curr];
}

strblobptr& strblobptr::incr()
{
	check(curr, "increment past end of strblobptr");
	++curr;
	return *this;
}


void strblob::check(size_type i, const string& msg) const
{
	if (i >= data->size())
		throw out_of_range(msg); //throw索引越界的异常
}

//访问元素
string& strblob::front()
{
	check(0, "front on empty strblob");
	return data->front(); //调用底层vector的front()方法作为返回值
}
const string& strblob::front() const
{
	check(0, "front on empty strblob");
	return data->front(); 
}
string& strblob::back()
{
	check(0, "front on empty strblob");
	return data->back();
}
const string& strblob::back() const
{
	check(0, "front on empty strblob");
	return data->back();
}
//删除元素
void strblob::pop_back()
{
	check(0, "pop_back on empty strblob");
	return data->pop_back();
}

//迭代器操作
strblobptr strblob::begin() 
{ 
	return strblobptr(*this); 
}

strblobptr strblob::end() 
{ 
	auto ret = strblobptr(*this, data->size()); 
	return ret; 
}

// StrBlobPtr 的比较操作
bool eq(const strblobptr& lhs, const strblobptr& rhs) {
	auto l = lhs.wptr.lock(), r = rhs.wptr.lock();
	// 若底层的 vector 是同一个
	if (l == r)
		// 则两个指针都是空,或者指向相同元素时,它们相等
		return (!r || lhs.curr == rhs.curr);
	else
		return false;       // 若指向不同 vector,则不可能相等
}

bool neq(const strblobptr& lhs, const strblobptr& rhs) {
	return !eq(lhs, rhs);
}

main.cpp

int main()
{
	fstream fin("infile.txt");
	string line;
	strblob strb;
	while (getline(fin, line))
	{
		strb.push_back(line);
	}

	
	for (strblobptr sbp(strb, 0); neq(sbp, strb.end()); sbp.incr())
		cout << sbp.deref() << endl;

	return 0;
}

Test 12.22

strblob.h

class conststrblobptr
{
public:
	conststrblobptr() : curr(0) {};
	conststrblobptr(const strblob& a, size_t sz = 0) : wptr(a.data), curr(sz) {};
	string& deref() const; //访问指针所指元素
	conststrblobptr& incr(); //递增指针

private:
	shared_ptr<vector<string>> check(size_t, const string&) const;
	weak_ptr<vector<string>> wptr;
	size_t curr;
};

strblob.cpp

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

string& conststrblobptr::deref() const
{
	auto p = check(curr, "dereference past end");
	return (*p)[curr];
}

conststrblobptr& conststrblobptr::incr()
{
	check(curr, "increment past end of strblobptr");
	++curr;
	return *this;
}

Test 12.23

int main()
{
	const char* cc1 = "hello "; 
	const char* cc2 = "world";

	unsigned len = strlen(cc1) + strlen(cc2) + 1;
	char* cp = new char[len]();

	strcat_s(cp, len, cc1);
	strcat_s(cp, len, cc2);

	for (int i = 0; i < 10; ++i)
		cout << *cp++ <<  " ";
    
    delete[] cp;

	string str1{ "hello " };
	string str2{ "world" };

	unsigned slen = str1.size() + str2.size() + 1;
	char* sp = new char[slen]();

	strcat_s(sp, slen, (str1 + str2).c_str());

	for (int i = 0; i < 10; ++i)
		cout << *sp++ << " ";
    
    delete[] sp;

	return 0;
}

Test 12.24

int main()
{
    size_t len = 5;
    char* r = new char[len + 1]();

    cin.get(r, len + 1);

    cout << r ;


    // 释放动态数组
    delete[] r;

    return 0;
}

使用cin.get()函数,只读取前len+1个字符

Test 12.26

int main()
{
    size_t n = 20;
    allocator<string> alloc;
    auto const p = alloc.allocate(n); //分配n个未初始化的string,p永远指向首元素

    auto q = p; //q指向首元素
    fstream fin("infile.txt");
    string str;
    while (fin >> str && q != p + n)
        alloc.construct(q++, str); //设置alloc中的元素,并让指针q递增直到alloc末元素的下一位置

    const size_t size = q - p; //表示我们读取了多少个元素

    cout << size;

    //销毁alloc中的元素并释放内存
    while (q != p)
        alloc.destroy(--q);

    alloc.deallocate(p, n);

    return 0;
}

Test 12.27 自定义TextQuery类

这里是自己实现的文件单词查询功能类,可以和书中的类进行比较,学习别人的优点

TextQuery.h

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

class TextQuery
{
	friend class QueryResult;

public:
	TextQuery();
	TextQuery(fstream& fin);

	void QueryWord(const string& word);

private:
	vector<string> fileline;
	map<string, set<int>> occurrow;
};

TextQuery…cpp

#include"TextQuery.h"
#include<sstream>
#include<algorithm>
#include<iostream>

TextQuery::TextQuery(fstream& fin)
{
	string line, word;
	int row = 1;
	while (getline(fin, line))
	{
		fileline.push_back(line);

		istringstream strin(line);
		//把单词和行号添加进map
		while (strin >> word)
			occurrow[word].insert(row);
		++row;
	}
}

void TextQuery::QueryWord(const string& word)
{
	if (occurrow.find(word) == occurrow.end())
		cout << "no word in file" << endl;
	else
	{
		cout << "element occur " << occurrow[word].size() << "times" << endl;

		for (auto& row : occurrow[word])
		{
			cout << "(line " << row << ") " << fileline[row - 1] << endl;
		}
			
	}
		
}

main.cpp

#include"TextQuery.h"

int main()
{
    fstream fin("infile.txt");
    TextQuery dict(fin);

    dict.QueryWord("you're");

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值