第十四章:向量、模板和异常 习题答案
本章实现的模板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];
}