本章实现的模板Vector
目前学到第十四章,对继承不熟,因此没有用到14.5.6中的vector_base类,因而没有实现vector类的RAII。
#include<iostream>
#include"14_8-Allocator.h"
template<typename T, typename A = allocator<T>>
class vector {
static const int first_expand_space{ 8 };
A alloc;
int sz;
int space;
T* elem;
public:
class Invalid {};
struct out_of_range { };
vector();
explicit vector(int x, T def = T{});
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);
int capacity()const;
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)
: 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()) }
{
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) }
{
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)
{
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 }
{
arg.sz = arg.space = 0;
arg.elem = nullptr;
}
template<typename T, typename A>
vector<T, A>& vector<T, A>::operator=(vector&& arg)
{
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)
{
if (newsize < 0)
throw Invalid{};
reserve(newsize);
for (int i = newsize; i < sz; ++i)
alloc.destroy(elem + i);
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)
{
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 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);
Link* add(Link* n);
Link* add_order(Link* n);
Link* erase();
Link* find(const string& s);
const Link* find(const string& s) const;
Link* advance(int 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)
{
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)
{
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)
{
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)
{
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 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)
{
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
#include"../../std_lib_facilities.h"
template<typename 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");
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;
}
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)
{
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
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using std::cerr;
template<typename T>class allocator {
public:
allocator() {}
T* allocate(int n);
void deallocate(T* p, int n);
void construct(T* p, const T& v);
void destroy(T* p);
};
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;
}
|