C++程序设计原理与实践 习题答案 第十四章 第14章习题答案

本章实现的模板Vector

目前学到第十四章,对继承不熟,因此没有用到14.5.6中的vector_base类,因而没有实现vector类的RAII。

//Vector_template.h

#include<iostream>
#include"14_8-Allocator.h"

//使用模板需要注意,目前VS2019都要求在使用模板的地方必须能得到模板的完整定义
//因此,我们将模板的定义都放在了头文件中

template<typename T, typename A = allocator<T>>
class vector {
	static const int first_expand_space{ 8 };
	A alloc;			//用 alloc 管理元素内存
	int sz;				//元素数目
	int space;			//总空间 = 元素数目 + 给新元素的空闲空间(槽位);总空间是指当前分配的空间
	T* elem;
public:
	class Invalid {};
	struct out_of_range { /*...*/ };	//用来报告越界错误

	vector();									//默认构造函数
	explicit vector(int x, T def = T{});		//构造函数,x为元素数量,def为初始化值,在定义中有默认值
	vector(std::initializer_list<T>lst);	//初始化器列表构造函数
	
	vector(const vector&);						//拷贝构造函数
	vector& operator=(const vector&);			//拷贝赋值函数
	
	vector(vector&&);							//移动构造函数
	vector& operator=(vector&&);				//移动赋值函数
	
	int size() const;
	void reserve(int newalloc);					//改变 space 的大小
	int capacity()const;						//返回 space 的大小
	void resize(int newalloc, T def = T{});		//该表元素数量
	void push_back(const T& val);

	T& operator[](int n);
	const T& operator[](int n) const;
	T& at(int n);
	const T& at(int n) const;
	
	~vector();
};


//下面是定义

template<typename T, typename A>
vector<T, A>::vector()
	:sz{ 0 }, space{ 0 }, elem{ nullptr }
{ }

template<typename T, typename A>
vector<T, A>::vector(int x, T def)
//构造函数,x为元素数量
	: sz{ x }, space{ x }
{
	if (x < 0)
		throw Invalid{};
	elem = alloc.allocate(x);
	for (int i = 0; i < sz; i++)
		alloc.construct(elem + i, def);	//初始化
}

template<typename T, typename A>
vector<T, A>::vector(std::initializer_list<T> lst)
//初始化器列表构造函数
	:sz{ int(lst.size()) }, space{ int(lst.size()) }, elem{ alloc.allocate(lst.size()) }
{
	//std::cout << "初始化列表构造函数\n";
	const T* ti = lst.begin();
	for (int i = 0; i < sz; ++i)
		alloc.construct(elem + i, *ti++);	//初始化
}

template<typename T, typename A>
vector<T, A>::vector(const vector& arg)
//拷贝构造函数
	: sz{ arg.sz }, space{ arg.space }, elem{ alloc.allocate(arg.space) }
{
	//std::cout << "拷贝构造函数\n";
	for (int i = 0; i < sz; ++i)
		alloc.construct(elem + i, arg.elem[i]);
}

template<typename T, typename A>
vector<T, A>& vector<T, A>::operator=(const vector& arg)
//拷贝赋值函数
{
	//std::cout << "拷贝赋值函数\n";
	if (this == &arg)				//自赋值,什么也不用做
		;
	else if (arg.sz <= space)		//空间足够,无需分配空间
	{
		for (int i = 0; i < sz; ++i)
			alloc.destroy(elem + i);				//先销毁原来的元素
		for (int i = 0; i < arg.sz; ++i)
			alloc.construct(&elem[i], arg.elem[i]);	//拷贝元素
		sz = arg.sz;
	}
	else
	{
		T* p = alloc.allocate(arg.sz);
		for (int i = 0; i < arg.sz; ++i)
			alloc.construct(p + i, arg.elem[i]);	//拷贝元素
		alloc.deallocate(elem, space);
		sz = space = arg.sz;		//设置新大小
		elem = p;					//指向新元素的指针
	}
	return *this;					//按照惯例,赋值运算符将返回被赋值对象的引用
}

template<typename T, typename A>
vector<T, A>::vector(vector&& arg)
//移动构造函数
	:sz{ arg.sz }, space{ arg.space }, elem{ arg.elem }
{
	//std::cout << "移动构造函数\n";
	arg.sz = arg.space = 0;		//令 arg 变为空
	arg.elem = nullptr;
}


template<typename T, typename A>
vector<T, A>& vector<T, A>::operator=(vector&& arg)
//移动赋值函数,将 arg 移动到本vector
{
	//std::cout << "移动赋值函数\n";
	alloc.deallocate(elem, space);
	sz = arg.sz;
	space = arg.space;
	elem = arg.elem;
	arg.sz = arg.space = 0;
	arg.elem = nullptr;
	return *this;
}

template<typename T, typename A>
int vector<T, A>::size() const
{
	return sz;
}

template<typename T, typename A>
void vector<T, A>::reserve(int newalloc)
{
	if (newalloc <= space)					//永远不会减少分配的空间
		return;
	T* p = alloc.allocate(newalloc);	//分配新空间
	for (int i = 0; i < sz; ++i)
		alloc.construct(&p[i], elem[i]);		//拷贝现有元素
	for (int i = 0; i < sz; ++i)
		alloc.destroy(&elem[i]);			//销毁现有元素
	alloc.deallocate(elem, space);			//释放旧空间
	elem = p;
	space = newalloc;
}

template<typename T, typename A>
int vector<T, A>::capacity() const
{
	return space;
}

template<typename T, typename A>
void vector<T, A>::resize(int newsize, T def)
//令 vector 有 newsize 个元素
//newsize 必须 >= 0
//用默认值 def 初始化每个新元素
{
	if (newsize < 0)
		throw Invalid{};
	reserve(newsize);
	for (int i = newsize; i < sz; ++i)
		alloc.destroy(elem + i);			//销毁从newsize开始的元素
	for (int i = sz; i < newsize; ++i)
		alloc.construct(&elem[i], def);		//用默认值初始化
	sz = newsize;
}

template<typename T, typename A>
void vector<T, A>::push_back(const T& val)
//将 vector 的大小增加1:用 val 初始化新元素
{
	if (space == 0)
		reserve(first_expand_space);
	else if (sz >= space)
		reserve(space * 2);
	alloc.construct(&elem[sz], val);
	++sz;
}

template<typename T, typename A>
T& vector<T, A>::operator[](int n)
{
	return elem[n];
}

template<typename T, typename A>
const T& vector<T, A>::operator[](int n) const
{
	return elem[n];
}

template<typename T, typename A>
T& vector<T, A>::at(int n)
{
	if (n < 0 || sz <= n)
		throw out_of_range();
	return elem[n];
}

template<typename T, typename A>
const T& vector<T, A>::at(int n) const
{
	if (n < 0 || sz <= n)
		throw out_of_range();
	return elem[n];
}

template<typename T, typename A>
vector<T, A>::~vector()
{
	for (int i = 0; i < sz; ++i)
		alloc.destroy(elem + i);		//释放之前要销毁对象元素
	alloc.deallocate(elem, space);	
}

14.1

#include"../../std_lib_facilities.h"

template<typename T> void f(vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() != v2.size())
	{
		cerr << "two vectors have different size\n";
		return;
	}
	for (int i = 0; i < v1.size; ++i)
		v1[i] += v2[i];
}

14.2

#include"../../std_lib_facilities.h"

template<typename T, typename U>	//T和U的限制为可以做乘法和加法的类型
T in_product(const vector<T>& vt, const vector<U>& vu)
{
	T res{ 0 };
	if (vt.size() != vu.size())
	{
		cerr << "two vectors have different size\n";
		return res;
	}
	for (int i = 0; i < vt.size(); ++i)
		res += vt[i] * vu[i];
	return res;
}

14.3

#include"../../std_lib_facilities.h"

template<typename T> class Pair {
	string var_name;
	T val;
public:
	Pair(string n, T v) :var_name{ n }, val{ v }{	}
	string get_name() { return var_name; }
	string get_name()const { return var_name; }
	T get_val() { return val; }
	const T& get_val()const { return val; }
	void change_val(T v) { val = v; }
};

vector<Pair<double>> var_tbl;

bool is_declared(string var)
{
	for (const Pair<double>& v : var_tbl)
		if (v.get_name() == var)
			return true;
	return false;
}

double define_name(string var, double val)
{
	if (is_declared(var))
		error(var, " declared twice");
	var_tbl.push_back(Pair<double>{var, val});
	return val;
}

14.4

#include"../../std_lib_facilities.h"

struct God {
	string name;
	string mythology;
	string mount;
	string weapon;
};

template<typename T>
class Link {
public:
	T god;

	Link(const God& g, Link* p = nullptr, Link* s = nullptr)
		:god{ g }, pred{ p }, succ{ s } { }

	Link* insert(Link* n);	//在此对象之前插入n
	Link* add(Link* n);		//在此对象之后插入n
	Link* add_order(Link* n);	//按字典序将n放置在正确位置中
	Link* erase();			//将此对象从链表中删除
	Link* find(const string& s);	//在链表中查找s
	const Link* find(const string& s) const;	//在const链表中查找s
	Link* advance(int n);		//在链表中移动n个位置
	Link* next() const { return succ; }
	Link* prev() const { return pred; }
private:
	Link* pred;
	Link* succ;
};

template<typename T>
void print_all(Link<T>* p);


int main()
try
{
	Link<God>* norse_gods = new Link<God>{ God{"Thor", "Norse","",""} };
	norse_gods = norse_gods->add_order(new Link<God>{ God{"Odin", "Norse","Eight-legged flying horse called Sleipner",""} });
	norse_gods = norse_gods->add_order(new Link<God>{ God{"Freia", "Norse", "",""} });
	print_all(norse_gods);
	cout << '\n';

	Link<God>* greek_gods = new Link<God>{ God{"Hera","Greek","",""} };
	greek_gods = greek_gods->insert(new Link<God>{ God{"Athena","Greek","",""} });
	greek_gods = greek_gods->add_order(new Link<God>{ God{"Ares" ,"Greek", "", ""} });
	greek_gods->add_order(new Link<God>{ God{"Zeus","Greek","",""} });
	greek_gods->add_order(new Link<God>{ God{"Poseidon","Greek","","Trident"} });
	print_all(greek_gods);
	cout << '\n';

	print_all(greek_gods->advance(2));
	cout << '\n';

	return 0;
}
catch (runtime_error& e)
{
	cerr << "Runtime error: " << e.what() << endl;
	return 1;
}
catch (...)
{
	cerr << "Exception occured!\n";
	return 2;
}

template<typename T>
Link<T>* Link<T>::insert(Link<T>* n)
//在此对象之前插入n
{
	if (n == nullptr)
		return this;
	if (this == nullptr)
		return n;
	n->succ = this;
	n->pred = pred;
	if (pred)
		pred->succ = n;
	pred = n;
	return n;
}

template<typename T>
Link<T>* Link<T>::add(Link<T>* n)
//在此对象之后插入n
{
	if (n == nullptr)
		return this;
	if (this == nullptr)
		return n;
	n->pred = this;
	n->succ = succ;
	if (succ)
		succ->pred = n;
	succ = n;
	return this;
}

template<typename T>
Link<T>* Link<T>::add_order(Link<T>* n)
//按字典序将n放置在正确位置中;返回在前的元素
{
	if (n == nullptr)
		return this;
	if (this == nullptr)
		return n;
	Link<T>* header = this;

	if (n->god.name < header->god.name)
	{
		n->pred = pred;
		n->succ = this;
		pred = n;
		header = n;
	}
	else if (n->god.name > header->god.name)
	{
		Link<T>* p;
		for (p = this; p->succ && n->god.name > p->succ->god.name; p = p->next())
			continue;
		n->succ = p->succ;
		n->pred = p;
		if (p->succ)
			p->succ->pred = n;
		p->succ = n;
	}
	return header;
}

template<typename T>
Link<T>* Link<T>::erase()
//将此对象从链表中删除;返回该对象的后继
{
	if (this == nullptr)
		return nullptr;
	if (pred)
		pred->succ = succ;
	if (succ)
		succ->pred = pred;
	return succ;
}

template<typename T>
Link<T>* Link<T>::find(const string& name)
//在链表中查找s
{
	Link<T>* p = this;
	while (p)
		if (p->god.name == name)
			break;
		else
			p = p->succ;
	return p;
}
template<typename T>
const Link<T>* Link<T>::find(const string& name) const
//在const链表中查找s
{
	const Link<T>* p = this;
	while (p)
		if (p->god.name == name)
			break;
		else
			p = p->succ;
	return p;
}

template<typename T>
Link<T>* Link<T>::advance(int n)
//在链表中移动n个位置
{
	Link<T>* p = this;
	if (n < 0)
	{
		while (n++)
			p = p->pred;
	}
	else if (n > 0)
		while (n--)
			p = p->succ;
	return p;
}


//辅助函数
template<typename T>
void print_all(Link<T>* p)
{
	cout << "{ ";
	God g;
	while (p)
	{
		g = p->god;
		cout << "( " << g.name << ", "
			<< g.mythology << ", "
			<< g.mount << ", "
			<< g.weapon << " )";
		if (p = p->next())
			cout << '\n';
	}
	cout << " }";
}

14.5, 14.6 and 14.7 Number

//Exercise 14.5, 14.6 and 14.7

#include"../../std_lib_facilities.h"


template<typename T>	//T应是数值类型
class Number {
	T n;
public:
	Number(T ini = T{}) :n{ ini } { }
	T get() const { return n; }
	void set(T v) { n = v; }
	Number& operator=(const Number& a);	//赋值运算符必须重载为类的非静态成员函数
};

template<typename T>
Number<T>& Number<T>::operator=(const Number<T>& a)
{
	n = a.get();
	return *this;
}


//二元运算符重载,如果不改变左操作数,那么一般重载为非成员函数
template<typename T>
Number<T> operator+(const Number<T>& a, const Number<T>& b)
{
	Number<T> res{ a.get() + b.get() };
	return res;
}

template<typename T>
Number<T> operator+=(Number<T>& a, const Number<T>& b)
{
	a.set(a.get() + b.get());
	return Number<T>{a.get()};
}

template<typename T>
Number<T> operator-(const Number<T>& a, const Number<T>& b)
{
	Number<T> res { a.get() - b.get() };
	return res;
}

template<typename T>
Number<T> operator*(const Number<T>& a, const Number<T>& b)
{
	Number<T> res { a.get()* b.get() };
	return res;
}

template<typename T>
Number<T> operator/(const Number<T>& a, const Number<T>& b)
{
	if (b.get() == 0)
		error("divide by zero");
	Number<T> res { a.get() / b.get() };
	return res;
}

template<typename T>
Number<T> operator%(const Number<T>& a, const Number<T>& b)
{
	if (b.get() == 0)
		error("mod by zero");
	//模运算可定义为 x % y = x - int(x / y) * y
	T res = a.get() - int(a.get() / b.get()) * b.get();
	return Number<T> {res};
}

template<typename T>
istream& operator>>(istream& is, Number<T>& n)
{
	T v;
	is >> v;
	n.set(v);
	return is;
}

template<typename T>
ostream& operator<<(ostream& os, const Number<T>& n)
{
	os << n.get();
	return os;
}

//专门针对习题7的乘法模板
template<typename T, typename U>
Number<T> operator*(const Number<T>& a, const Number<U>& b)
{
	Number<T> res{ a.get() * b.get() };
	return res;
}

//template<typename T, typename U>
//T in_product(const vector<T>& vt, const vector<U>& vu);
//VS2019仍然要求在使用模板的地方必须能够得到模板的完整定义,所以上面的声明是不行的,必须得是下面的完整定义
template<typename T, typename U>	//T和U的限制为可以做乘法和加法的类型
T in_product(const vector<T>& vt, const vector<U>& vu)
{
	T res{ 0 };
	if (vt.size() != vu.size())
	{
		cerr << "two vectors have different size\n";
		return res;
	}
	for (size_t i = 0; i < vt.size(); ++i)
		res += vt[i] * vu[i];
	return res;
}

int main()
try
{
	Number<int>a{ 1 };
	Number<int>b;
	cout << "int a = " << a << '\n';
	a = Number<int>{ 72 };
	cout << "a = Number<int>{ 72 } : a = " << a << '\n';
	cout << "int b = " << b << '\n';
	cin >> b;
	cout << "cin >> b --> int b = " << b << '\n';
	cout << "a + b = " << a + b << '\n';
	cout << "a - b = " << a - b << '\n';
	cout << "a * b = " << a * b << '\n';
	cout << "a / b = " << a / b << '\n';
	cout << "a % b = " << a % b << '\n';


	Number<double>x{ 1.2 };
	Number<double>y;
	cout << "double x = " << x << '\n';
	cout << "double y = " << y << '\n';
	x = Number<double>{ 7.2 };
	cout << "x = Number<double>{ 7.2 } --> x = " << x << '\n';
	cin >> y;
	cout << "cin >> y --> double y = " << y << '\n';
	cout << "x + y = " << x + y << '\n';
	cout << "x - y = " << x - y << '\n';
	cout << "x * y = " << x * y << '\n';
	cout << "x / y = " << x / y << '\n';
	cout << "x % y = " << x % y << '\n';

	vector<Number<double>>vt{ x, y };
	vector<Number<int>>vu{ a, b };
	Number<double> res = in_product(vt, vu);
	cout << "vt .* vu = " << res << '\n';

	return 0;
}
catch (runtime_error& e) {
	cerr << "Runtime error: " << e.what() << endl;
	return 1;
}
catch (...) {
	cerr << "Exception occured!\n";
	return 2;
}

14.8 Allocator

14_8-Allocator.h

//14_8-Allocator.h

#include<iostream>
#include<stdio.h>
#include<stdlib.h>

using std::cerr;

template<typename T>class allocator {
public:
	allocator() {}

	T* allocate(int n);					//为n个类型为T的对象分配空间
	void deallocate(T* p, int n);		//释放从p开始的n个类型为T的对象

	void construct(T* p, const T& v);	//在地址p构造一个值为v的T类型对象
	void destroy(T* p);					//销毁p中的T

};

template<typename T>
T* allocator<T>::allocate(int n)
{
	T* p = (T*)malloc(n * sizeof(T));
	if (p == NULL)
	{
		fprintf(stderr, "allocating fail\n");
		return nullptr;
	}
	return p;
}

template<typename T>
void allocator<T>::deallocate(T* p, int n)
{
	if (n < 0)
	{
		cerr << "deallocate fail: n can not be negative\n";
		return;
	}
	if (n == 0)
		return;
	free(p);
}

template<typename T>
void allocator<T>::construct(T* p, const T& v)
{
	new (p) T{ v };
}

template<typename T>
void allocator<T>::destroy(T* p)
{
	p->~T();
}

14.9

template<typename T, typename A>
vector<T, A>& vector<T, A>::operator=(const vector& arg)
{
	if (this == &arg)				//自赋值,什么也不用做
		;
	else if (arg.sz <= space)		//空间足够,无需分配空间
	{
		for (int i = 0; i < sz; ++i)
			alloc.destroy(elem + i);				//先销毁原来的元素
		for (int i = 0; i < arg.sz; ++i)
			alloc.construct(&elem[i], arg.elem[i]);	//拷贝元素
		sz = arg.sz;
	}
	else
	{
		T* p = alloc.allocate(arg.sz);
		for (int i = 0; i < arg.sz; ++i)
			alloc.construct(p + i, arg.elem[i]);	//拷贝元素
		alloc.deallocate(elem, space);
		sz = space = arg.sz;		//设置新大小
		elem = p;					//指向新元素的指针
	}
	return *this;					//按照惯例,赋值运算符将返回被赋值对象的引用
}

14.10 naive unique_ptr

非常简单的一个 unique_ptr 实现,虽然没有实现其赋值操作或拷贝构造函数,但是不知道怎么阻止其默认拷贝操作,所以默认的赋值操作仍然可以运行的。。。

#include<iostream>
#include<vector>

using std::cout;
using std::cerr;
using std::endl;
using std::vector;

template<class T> class unique_ptr {
public:
	explicit unique_ptr(T* p) :pobj{ p } { }

	T& operator*();
	T* operator->();
	T* release();

	~unique_ptr() { delete pobj; }

private:
	T* pobj;
};

template<class T>
T& unique_ptr<T>::operator*()
{
	return *pobj;
}

template<class T>
T* unique_ptr<T>::operator->()
{
	return pobj;
}

template<class T>
T* unique_ptr<T>::release()
{
	T* temp = pobj;
	pobj = nullptr;
	return temp;
}

void is_free()
{
	//调用这个函数,使用vs2019的诊断工具的堆分析查看调用前后的堆情况
	unique_ptr<double>pdarr{ new double[5]{0.0,1.1,2.2,3.3,4.4} };
}


vector<int>* test_vector()
{
	unique_ptr<vector<int>> pv{ new vector<int> };
	cout << "unique_ptr<vector<int>> pv{ new vector<int> }; pv->size = " << pv->size() << endl;
	cout << "pv->push_back(i)...\n";
	for (size_t i = 0; i < 10; ++i)
		pv->push_back(i);
	cout << "After push_back:\n";
	for (int x : *pv)
		cout << x << ' ';
	cout << endl;
	return pv.release();
}

void test_release()
{
	vector<int>* pv = test_vector();
	cout << "vector<int>* pv = test_vector(); element of pv:\n";
	for (int x : *pv)
		cout << x << ' ';
	cout << endl;
	delete pv;
}

int main()
try
{
	unique_ptr<double> pd{ new double {5.5} };
	cout << "unique_ptr<double> pd{ new double {5.5} } --> *pd = " << *pd << endl;
	*pd = 6.6;
	cout << "*pd = 6.6; --> *pd = " << *pd << endl;
	
	is_free();
	test_release();

	return 0;
}
catch (...) {
	cerr << "Exception occured!\n";
	return 2;
}

14.11 counted_ptr

#include<iostream>
#include<vector>

using std::cout;
using std::cerr;
using std::endl;
using std::vector;

template<class T> class counted_ptr {
public:
	explicit counted_ptr(T ini = T{});	//构造函数,在自由存储区中为T对象和其“使用计数”分配空间,并给T对象设置初始值ini
	counted_ptr(const counted_ptr&);	//拷贝构造函数

	counted_ptr& operator=(const counted_ptr&);		//拷贝赋值

	T& operator*();
	T* operator->();

	~counted_ptr();

private:
	T* pobj;
	int* pcnt;	//指向“使用计数”的指针
};

template<class T>
counted_ptr<T>::counted_ptr(T ini)
	:pobj{ new T {ini} }, pcnt{ new int {1} }
{	}

template<class T>
counted_ptr<T>::counted_ptr(const counted_ptr& cp)
	:pobj{cp.pobj},pcnt{cp.pcnt}
{
	++(*pcnt);
}

template<class T>
counted_ptr<T>& counted_ptr<T>::operator=(const counted_ptr& cp)
{
	if (this == &cp || pobj == cp.pobj)		//自赋值或者被赋值为已经指向的对象的计数指针,什么也不需要做
		return *this;
	if (pcnt && --(*pcnt) <= 0)		//如果它是最后一个指向T对象的计数指针
	{
		delete pobj;
		delete pcnt;
	}
	pobj = cp.pobj;
	pcnt = cp.pcnt;
	++(*pcnt);
	return *this;
}

template<class T>
T& counted_ptr<T>::operator*()
{
	return *pobj;
}

template<class T>
T* counted_ptr<T>::operator->()
{
	return pobj;
}

template<class T>
counted_ptr<T>::~counted_ptr()
{
	if (--(*pcnt) == 0)
	{
		delete pobj;
		delete pcnt;
	}
}

template<class T>
void is_free(counted_ptr<T> cp)
{
	//调用这个函数,使用vs2019的诊断工具的堆分析查看调用前后的堆情况
	counted_ptr<double>pdarr;
}

template<class T>
counted_ptr<vector<int>> test_vector(counted_ptr<T> cp)
{
	counted_ptr<vector<int>> pv{ vector<int>{} };
	cout << "counted_ptr<vector<int>> pv{ new vector<int> }; pv->size = " << pv->size() << endl;
	cout << "pv->push_back(i)...\n";
	for (size_t i = 0; i < 10; ++i)
		pv->push_back(i);
	cout << "After push_back:\n";
	for (int x : *pv)
		cout << x << ' ';
	cout << endl;
	return pv;
}

template<class T>
void test_release(counted_ptr<T>& cp)
{
	counted_ptr<vector<int>> pv = test_vector(cp);
	cout << "vector<int>* pv = test_vector(); element of pv:\n";
	for (int x : *pv)
		cout << x << ' ';
	cout << endl;
}

int main()
try
{
	counted_ptr<double> pd {5.5};
	cout << "counted_ptr<double> pd{ new double {5.5} } --> *pd = " << *pd << endl;
	*pd = 6.6;
	cout << "*pd = 6.6; --> *pd = " << *pd << endl;

	is_free(pd);
	test_release(pd);

	return 0;
}
catch (...) {
	cerr << "Exception occured!\n";
	return 2;
}

14.12

这题的测试我不太会

#include"../../std_lib_facilities.h"

class File_handle {
public:
	explicit File_handle(const string&);
	~File_handle() { fs.close(); }

	template<class T> fstream& operator>>(T&);
	template<class T> fstream& operator<<(T&);

private:
	fstream fs;
};

File_handle::File_handle(const string& fname)
	:fs{fname, ios_base::in|ios_base::out}
{
	if (!fs)
		error("can't open file ", fname);
}

template<class T>
fstream& File_handle::operator>>(T& idata)
{
	fs >> idata;
	return fs;
}

template<class T>
fstream& File_handle::operator<<(T& odata)
{
	fs << odata;
	if (!fs)
		error("can't output ", odata);
	return fs;
}


int main()
try
{
	string fname{ "14_12.txt" };
	File_handle fh(fname);
	
	//我的现有知识发现,对于文件流来说,要么读,要么写,做不到先写再读或者先读再写
	//或许可以显式刷新流,做到先写再读或者先读再写
	double odata{ 1.0 };
	fh << odata;

	/*string idata;
	fh >> idata;
	cout << "input data from " << fname << ": " << idata;*/

	return 0;
}
catch (runtime_error& e)
{
	cerr << "Runtime error: " << e.what() << endl;
	return 1;
}

14.13 观察RAII管理对象的方式

#include"../../std_lib_facilities.h"

class Tracer {
public:
	explicit Tracer(const string& s) :str{ s } 
	{
		cout << "Tracer: " << s << endl;
	}
	~Tracer()
	{
		cout << "~Tracer: " << str << endl;
	}

	Tracer(const Tracer&);
	Tracer& operator=(const Tracer&);
private:
	string str;
};

Tracer::Tracer(const Tracer& tr)
	:str{tr.str}
{
	cout << "Tracer Copy Construction: " << str << endl;
}

Tracer& Tracer::operator=(const Tracer& tr)
{
	cout << "Tracer Copy assignment old string: " << str << endl;
	str = tr.str;
	cout << "Tracer Copy assignment: " << str << endl;
	return *this;
}




//测试部分
class Test_class {
	Tracer m_obj;	//类内成员对象
public:
	Test_class() :m_obj{"Member object of Test_class"}{	}
	Test_class& operator=(const Test_class&);
};

Test_class& Test_class::operator=(const Test_class& tc)
{
	cout << "Test_class Copy Assignment: \n";
	m_obj = tc.m_obj;
	return *this;
}

Tracer func_call(Tracer& tr);

Tracer g_obj{ "Global object" };	//全局对象

int main()
{
	Tracer loc_obj1{ "Local object 1" };	//局部对象1
	Tracer loc_obj2{ "Local object 2" };	//局部对象2
	Tracer loc_obj3{ func_call(loc_obj2) };	//局部对象3
	loc_obj2 = loc_obj1;

	Tracer* fs_obj = new Tracer{ "Free stroe object" };	//自由空间分配的对象
	Test_class tc1;	//测试类内成员对象
	Test_class tc2;	//测试类内成员对象
	tc2 = tc1;
	delete fs_obj;	//释放对象

	return 0;
}

Tracer func_call(Tracer& tr)
{
	Tracer loc_obj3{ tr };
	return loc_obj3;
}

14.14 and 14.15 未实现

14.16

这题没怎么测试,可能会有潜在的bug

//和书上不一样的vector_base

#include<iostream>

template<typename T> struct vector_base {
	static const int first_expand_space{ 8 };
	int sz;
	int space;
	T* elem;

	vector_base() :sz{ 0 }, space{ 0 }, elem{ nullptr }{}
	vector_base(int n, T ini);
	vector_base(std::initializer_list<T>lst);	//初始化器列表构造函数
	vector_base(const vector_base& arg);		//拷贝构造函数
	vector_base& operator=(const vector_base& arg);	//拷贝赋值函数
	~vector_base() { delete[] elem; }

	void reserve(int newalloc);
	void resize(int newsize, T ini);
	void push_back(const T& val);
};

template<typename T>
vector_base<T>::vector_base(int n, T ini)
	:sz{ n }, space{ n }, elem{ new T[n] }
{
	for (int i = 0; i < n; ++i)
		elem[i] = ini;
}

template<typename T>
vector_base<T>::vector_base(std::initializer_list<T> lst)
//初始化器列表构造函数
	:sz{ int(lst.size()) }, space{ int(lst.size()) }, elem{ new T[lst.size()] }
{
	//std::cout << "初始化列表构造函数\n";
	std::copy(lst.begin(), lst.end(), elem);	//初始化
}

template<typename T>
vector_base<T>::vector_base(const vector_base& arg)
//拷贝构造函数
	: sz{ arg.sz }, space{ arg.sz }, elem{ new T[arg.sz] }
{
	//std::cout << "拷贝构造函数\n";
	std::copy(arg.elem, arg.elem + arg.sz, elem);
}

template<typename T>
vector_base<T>& vector_base<T>::operator=(const vector_base& arg)
//拷贝赋值函数
{
	//std::cout << "拷贝赋值函数\n";
	if (this == &arg)				//自赋值,什么也不用做
		;
	else if (arg.sz <= space)		//空间足够,无需分配空间
	{
		for (int i = 0; i < arg.sz; ++i)
			elem[i] = arg.elem[i];	//拷贝元素
		sz = arg.sz;
	}
	else
	{
		T* p = new T[arg.sz];
		std::copy(arg.elem, arg.elem + arg.sz, p);//拷贝元素
		delete[] elem;
		sz = space = arg.sz;		//设置新大小
		elem = p;					//指向新元素的指针
	}
	return *this;					//按照惯例,赋值运算符将返回被赋值对象的引用
}

template<typename T>
void vector_base<T>::reserve(int newalloc)
{
	if (newalloc <= space)					//永远不会减少分配的空间
		return;
	T* p = new T[newalloc];				//分配新空间
	std::copy(elem, elem + sz, p);		//拷贝现有元素
	delete[] elem;						//释放旧空间
	elem = p;
	space = newalloc;
}

template<typename T>
void vector_base<T>::resize(int newsize, T ini)
//令 vector_base 有 newsize 个元素
//newsize 必须 >= 0
//用默认值 ini 初始化每个新元素
{
	reserve(newsize);
	for (int i = sz; i < newsize; ++i)
		elem[i] = ini;		//用默认值初始化
	sz = newsize;
}

template<typename T>
void vector_base<T>::push_back(const T& val)
//将 vector 的大小增加1:用 val 初始化新元素
{
	if (space == 0)
		reserve(first_expand_space);
	else if (sz >= space)
		reserve(space * 2);
	elem[sz] = val;
	++sz;
}



//下面是封装的Vector

template<typename T> class vector {
public:
	class Invalid {};
	struct out_of_range { /*...*/ };	//用来报告越界错误

	vector() :pvb{ nullptr } {}
	vector(int n, T ini = T{});
	vector(std::initializer_list<T> lst) :pvb{ new vector_base<T>{lst} }{}		//初始化器列表构造函数

	vector(const vector& arg) : pvb{ new vector_base<T>{*arg.pvb} } {}						//拷贝构造函数
	vector& operator=(const vector&);			//拷贝赋值函数

	vector(vector&&);							//移动构造函数
	vector& operator=(vector&&);				//移动赋值函数

	~vector() { delete pvb; }

	int size() const;
	void reserve(int newalloc);					//改变 space 的大小
	int capacity()const;						//返回 space 的大小
	void resize(int newalloc, T ini = T{});		//该表元素数量
	void push_back(const T& val);

	T& operator[](int n);
	const T& operator[](int n) const;
	T& at(int n);
	const T& at(int n) const;

private:
	vector_base<T>* pvb;
};

template<typename T>
vector<T>::vector(int n, T ini)
{
	if (n <= 0)
		pvb = nullptr;
	else
		pvb = new vector_base<T>(n, ini);
}

template<typename T>
vector<T>& vector<T>::operator=(const vector& arg)
//拷贝赋值函数
{
	//std::cout << "拷贝赋值函数\n";
	if (this != &arg)				//如果是自赋值,什么也不用做
	{
		if (pvb == nullptr)
			pvb = new vector_base<T>{ *arg.pvb };
		else
			*pvb = *(arg.pvb);
	}
	return *this;					//按照惯例,赋值运算符将返回被赋值对象的引用
}

template<typename T>
vector<T>::vector(vector&& arg)
//移动构造函数
	:pvb{ arg.pvb }
{
	//std::cout << "移动构造函数\n";
	arg.pvb = nullptr;
}

template<typename T>
vector<T>& vector<T>::operator=(vector&& arg)
//移动赋值函数,将 arg 移动到本vector
{
	//std::cout << "移动赋值函数\n";
	delete pvb;
	pvb = arg.pvb;
	arg.pvb = nullptr;
	return *this;
}

template<typename T>
int vector<T>::size() const
{
	if (pvb == nullptr)
		return 0;
	else
		return pvb->sz;
}

template<typename T>
void vector<T>::reserve(int newalloc)
{
	if (newalloc <= 0)
		return;
	if (pvb == nullptr)
		pvb = new vector_base<T>();
	pvb->reserve(newalloc);
}

template<typename T>
int vector<T>::capacity() const
{
	return pvb->space;
}

template<typename T>
void vector<T>::resize(int newsize, T ini)
//令 vector 有 newsize 个元素
//newsize 必须 >= 0
//用默认值 ini 初始化每个新元素
{
	if (newsize < 0)
		throw Invalid{};
	if (newsize == 0 && pvb == nullptr)
		return;
	else if (pvb == nullptr)
		pvb = new vector_base<T>();
	pvb->resize(newsize, ini);
}

template<typename T>
void vector<T>::push_back(const T& val)
//将 vector 的大小增加1:用 val 初始化新元素
{
	if (pvb == nullptr)
		pvb = new vector_base<T>();
	pvb->push_back(val);
}

template<typename T>
T& vector<T>::operator[](int n)
{
	return pvb->elem[n];
}

template<typename T>
const T& vector<T>::operator[](int n) const
{
	return pvb->elem[n];
}

template<typename T>
T& vector<T>::at(int n)
{
	if (n < 0 || pvb->sz <= n)
		throw out_of_range();
	return pvb->elem[n];
}

template<typename T>
const T& vector<T>::at(int n) const
{
	if (n < 0 || pvb->sz <= n)
		throw out_of_range();
	return pvb->elem[n];
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值