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

Accelerated C++ 习题解答 第11章

2014-04-01 17:11 369 查看
EX.11-0

#ifndef VEC_H
#define VEC_H

#include <algorithm>
#include <cstddef>
#include <memory>

using std::max;

template <class T> class Vec {
public:
typedef T* iterator;
typedef const T* const_iterator;
typedef size_t size_type;
typedef T value_type;//value_type是容器中存储的每个对象的类型
typedef T& reference;//reference和const_reference是value_type&和const value_type&的同义词
typedef const T& const_reference;

Vec() { create(); }//默认构造函数不带任何参数,它首先清空Vec类的对象,通过调用create成员函数实现
//第二个参数是一个默认变量
//这个构造函数事实上定义了两个构造函数,一个是使用size_t作参数,另一个则用到两个参数(一个size_t类型,一个const T&类型)
explicit Vec(size_type n, const T& t = T()) { create(n, t); }

Vec(const Vec& v) { create(v.begin(), v.end()); }//复制构造函数
Vec& operator=(const Vec&);	//赋值运算符函数
~Vec() { uncreate(); }//析构函数

//[]运算符函数
T& operator[](size_type i) { return data[i]; }
const T& operator[](size_type i) const { return data[i]; }

void push_back(const T& t) {
if (avail == limit)
grow();
unchecked_append(t);
}

size_type size() const { return avail - data; }

iterator begin() { return data; }
const_iterator begin() const { return data; }

iterator end() { return avail; }
const_iterator end() const { return avail; }

void clear() { uncreate(); }
bool empty() const { return data == avail; }

private:
iterator data;	// Vec中的首元素
iterator avail;	// Vec中末元素后面的一个元素
iterator limit;	// 新分配的内存中末元素后面一个元素

// 内存分配工具
std::allocator<T> alloc;	// 控制内存分配的对象

// 为底层数组分配空间并对其进行初始化
void create();
void create(size_type, const T&);
void create(const_iterator, const_iterator);

// 删除数组中的元素并释放其内存
void uncreate();

// 支持push_back函数
void grow();
void unchecked_append(const T&);
};

//不带任何参数的create函数仅生成一个空的Vec类型对象,它的工作只是使指针指向零地址
template <class T> void Vec<T>::create()
{
data = avail = limit = 0;
}

//根据size_type分配一定大小的内存空间
//由于allocate函数分配的内存没有被初始化,因此必须调用uninitialized_fill函数以便对它进行初始化
template <class T> void Vec<T>::create(size_type n, const T& val)
{
data = alloc.allocate(n);
limit = avail = data + n;
std::uninitialized_fill(data, limit, val);
}

//调用uninitialized_copy函数初始化allocate函数分配的内存空间
template <class T>
void Vec<T>::create(const_iterator i, const_iterator j)
{
data = alloc.allocate(j - i);
limit = avail = std::uninitialized_copy(i, j, data);
}

//运行析构函数,删除该对象,并释放其占用的内存
template <class T> void Vec<T>::uncreate()
{
if (data) {
iterator it = avail;
while (it != data)
alloc.destroy(--it);

alloc.deallocate(data, limit - data);
}
data = limit = avail = 0;

}

template <class T> void Vec<T>::grow()
{
//如果Vec对象是空的,则选择一个元素进行内存分配,若非空,则以当前空间的两倍大小进行内存分配
size_type new_size = max(2 * (limit - data), ptrdiff_t(1));

iterator new_data = alloc.allocate(new_size);

iterator new_avail = std::uninitialized_copy(data, avail, new_data);

uncreate();

data = new_data;
avail = new_avail;
limit = data + new_size;
}

template <class T> void Vec<T>::unchecked_append(const T& val)
{
alloc.construct(avail++, val);
}

template <class T>
Vec<T>& Vec<T>::operator=(const Vec& rhs)
{
if (&rhs != this) {

uncreate();

create(rhs.begin(), rhs.end());
}
return *this;
}

#endif


EX.11-1

在编写类时,如果没有显示地定义这些操作,编译器会自动为类生成相应版本的函数,进行一些默认的操作。这些默认的函数被定义成以系列的递归的操作--对每个成员按照它们相应的类型规则进行复制、赋值或者删除。

EX.11-2

如果类中不存在定义任何构造函数,那么编译器将自动生成一个默认的不带任何参数的构造函数。这一自动生成的构造函数通过一种对象自身在初始化时采取的方式,对其成员数据进行递归初始化。

EX.11-3

Student_info对象在调用自动生成的赋值操作函数时会删去对象中原本存在的值,然后代之以新的值。赋值操作要将运算符右操作数对象的每一个元素的值都复制过去。

EX.11-4

通过默认析构函数删除一个指针变量时,不会释放该指针指向的对象占用的内存空间。

默认的析构函数不能删除new运算符在自由存储器中分配的对象或对象成员。如果类成员占用的空间是在构造函数中动态分配的,我们就必须自定义析构函数,然后显式使用delete运算符来释放构造函数使用new运算符分配的内存,就像销毁普通变量一样。

Student_info中自动生成的析构函数删除了2个成员变量,即midterm和final。

EX.11-5

Student_info.h

#pragma once

#include <iostream>
#include <string>
#include "Vec.h"

struct Student_info {
public:
std::string name;
double midterm, final;
Vec<double> homework;

Student_info() { print("create"); }

Student_info(const Student_info& other) {
print("copy");
clone(other);
}

Student_info& operator=(const Student_info& other) {
print("assign");
if (this != &other)
clone(other);
return *this;
}

~Student_info() { print("destroy"); }

private:
void print(const std::string&);
void clone(const Student_info& other) {
name = other.name;
midterm = other.midterm;
final = other.final;
homework = other.homework;
}
};

bool compare(const Student_info&, const Student_info&);
std::istream& read(std::istream&, Student_info&);
std::istream& read_hw(std::istream&, Vec<double>&);


Student_info.cpp

#include "Student_info.h"

using namespace std;

void Student_info::print(const string& s) {
cout << s << endl;
}

bool compare(const Student_info& x, const Student_info& y)
{
return x.name < y.name;
}

istream& read(istream& is, Student_info& s)
{
is >> s.name >> s.midterm >> s.final;

read_hw(is, s.homework);
return is;
}

istream& read_hw(istream& in, Vec<double>& hw)
{
if (in) {
// 清除之前的内容
hw.clear();

double x;
while (in >> x)
hw.push_back(x);

// 清除流以使输入动作对下一个学生有效
in.clear();
}
return in;
}


EX.11-6

#ifndef VEC_H
#define VEC_H

#include <algorithm>
#include <cstddef>
#include <memory>

using std::max;

template <class T> class Vec {
public:
typedef T* iterator;
typedef const T* const_iterator;
typedef size_t size_type;
typedef T value_type;//value_type是容器中存储的每个对象的类型
typedef T& reference;//reference和const_reference是value_type&和const value_type&的同义词
typedef const T& const_reference;

Vec() { create(); }//默认构造函数不带任何参数,它首先清空Vec类的对象,通过调用create成员函数实现
//第二个参数是一个默认变量
//这个构造函数事实上定义了两个构造函数,一个是使用size_t作参数,另一个则用到两个参数(一个size_t类型,一个const T&类型)
explicit Vec(size_type n, const T& t = T()) { create(n, t); }

Vec(const Vec& v) { create(v.begin(), v.end()); }//复制构造函数
Vec& operator=(const Vec&);	//赋值运算符函数
~Vec() { uncreate(); }//析构函数

//[]运算符函数
T& operator[](size_type i) { return data[i]; }
const T& operator[](size_type i) const { return data[i]; }

void push_back(const T& t) {
if (avail == limit)
grow();
unchecked_append(t);
}

size_type size() const { return avail - data; }

iterator begin() { return data; }
const_iterator begin() const { return data; }

iterator end() { return avail; }
const_iterator end() const { return avail; }

void clear() { uncreate(); }
bool empty() const { return data == avail; }

iterator erase(iterator position) {
for (iterator i = position; i != avail; ++i) {
alloc.destroy(i);
if ((i + 1) != avail)
alloc.construct(i, *(i + 1));
}

--avail;
return position;
}

private:
iterator data;	// Vec中的首元素
iterator avail;	// Vec中末元素后面的一个元素
iterator limit;	// 新分配的内存中末元素后面一个元素

// 内存分配工具
std::allocator<T> alloc;	// 控制内存分配的对象

// 为底层数组分配空间并对其进行初始化
void create();
void create(size_type, const T&);
void create(const_iterator, const_iterator);

// 删除数组中的元素并释放其内存
void uncreate();

// 支持push_back函数
void grow();
void unchecked_append(const T&);
};

//不带任何参数的create函数仅生成一个空的Vec类型对象,它的工作只是使指针指向零地址
template <class T> void Vec<T>::create()
{
data = avail = limit = 0;
}

//根据size_type分配一定大小的内存空间
//由于allocate函数分配的内存没有被初始化,因此必须调用uninitialized_fill函数以便对它进行初始化
template <class T> void Vec<T>::create(size_type n, const T& val)
{
data = alloc.allocate(n);
limit = avail = data + n;
std::uninitialized_fill(data, limit, val);
}

//调用uninitialized_copy函数初始化allocate函数分配的内存空间
template <class T>
void Vec<T>::create(const_iterator i, const_iterator j)
{
data = alloc.allocate(j - i);
limit = avail = std::uninitialized_copy(i, j, data);
}

//运行析构函数,删除该对象,并释放其占用的内存
template <class T> void Vec<T>::uncreate()
{
if (data) {
iterator it = avail;
while (it != data)
alloc.destroy(--it);

alloc.deallocate(data, limit - data);
}
data = limit = avail = 0;

}

template <class T> void Vec<T>::grow()
{
//如果Vec对象是空的,则选择一个元素进行内存分配,若非空,则以当前空间的两倍大小进行内存分配
size_type new_size = max(2 * (limit - data), ptrdiff_t(1));

iterator new_data = alloc.allocate(new_size);

iterator new_avail = std::uninitialized_copy(data, avail, new_data);

uncreate();

data = new_data;
avail = new_avail;
limit = data + new_size;
}

template <class T> void Vec<T>::unchecked_append(const T& val)
{
//construct成员函数在尚未被初始化的内存区域中构造单个对象,第一个参数是allocate函数已分配的内存指针,第二个参数是用于复制到该内存块的值
alloc.construct(avail++, val);
}

template <class T>
Vec<T>& Vec<T>::operator=(const Vec& rhs)
{
if (&rhs != this) {

uncreate();

create(rhs.begin(), rhs.end());
}
return *this;
}

#endif


EX.11-7

以下是测试分割字符串

#include <iostream>
#include <string>
#include <conio.h>

#include "Vec.h"

using namespace std;

Vec<string> split(const string& s)
{
Vec<string> ret;
typedef string::size_type string_size;
string_size i= 0;

while (i != s.size()) {
while (i != s.size() && isspace(s[i]))
++i;

string_size j = i;

while (j != s.size() && !isspace(s[j]))
++j;

if (i != j) {
ret.push_back(s.substr(i, j-i));
i = j;
}
}
return ret;
}

int main()
{
string s;
while (getline(cin, s)) {
Vec<string> v = split(s);

//for (Vec<string>::size_type i = 0; i != v.size(); ++i)
//	cout << v[i] << endl;

for (Vec<string>::const_iterator iter = v.begin(); iter != v.end(); ++iter)
cout << *iter << endl;
}
getch();
return 0;
}


测试第9章Student_info程序时也是同样,将使用vector类的地方换成使用Vec类

EX.11-8

List.h

#pragma once

#include <cstdarg>
#include <memory>

template <class T> class list {
template <class U> friend list<U> cons(const U&, const list<U>&);
template <class U> friend U car(const list<U>&);
template <class U> friend list<U> cdr(const list<U>&);
template <class U> friend size_t length(const list<U>&);

public:
typedef T* iterator;
typedef const T* const_iterator;
typedef size_t size_type;
typedef T value_type;
typedef std::ptrdiff_t difference_type;
typedef T& reference;
typedef const T& const_reference;

list() { resize(0); }
list(const list& other) { clone(other.data, other.avail); }
list(const_iterator b, const_iterator e) { clone(b, e); }
list& operator=(const list&);
~list() { destroy(); }

const_iterator begin() const { return data; }
const_iterator end() const { return avail; }

private:
iterator data;
iterator avail;
std::allocator<value_type> alloc;

void clone(const_iterator, const_iterator);
void destroy();
void resize(size_type);
};

template <class T> bool is_null(const list<T>&);
template <class T> T list_ref(const list<T>&, size_t);
template <class T> list<T> append(const list<T>&, const list<T>&);
template <class T> list<T> reverse(const list<T>&);
template <class T> list<T> member(const T&, const list<T>&);

template <class T> std::ostream& operator<<(std::ostream&, const list<T>&);

//***************************** Class public functions **************************//
//赋值运算符函数
template <class T> list<T>& list<T>::operator=(const list<T>& other) {
//判断是否进行自我复制
if (this != &other) {
//删除运算符左侧的数组
destroy();
//从右侧复制元素到左侧
clone(other.data, other.avail);
}
//this关键词只在成员函数内部才有效,代表指向函数操作的对象的指针
return *this;
}

//***************************** Class private functions **************************//
template <class T> void list<T>::clone(const_iterator b, const_iterator e) {
resize(e - b);
//调用uninitialized_copy函数初始化allocate函数分配的内存空间
//将第一、第二个参数所指向的区间内的值复制到第三个参数指向的内存空间中
uninitialized_copy(b, e, data);
}

template <class T> void list<T>::destroy() {
if (data) {
for (iterator it = data; it != avail; ++it)
alloc.destroy(it);
alloc.deallocate(data, avail - data);
}
data = avail = 0;
}

//分配n个大小的内存空间并指定头指针和尾指针
template <class T> void list<T>::resize(size_type n) {
data = alloc.allocate(n);
avail = data + n;
}

//**************************** Friend functions *********************************//
//将值e插入到list中,且被插入的值为list的data指针所指向的元素
template <class T> list<T> cons(const T& e, const list<T>& l) {
list<T> new_l;
//为new_l分配length(l) + 1大小的内存空间
new_l.resize(length(l) + 1);
//construct成员函数在尚未被初始化的内存区域中构造单个对象,第一个参数是allocate函数已分配的内存指针,第二个参数是用于复制到该内存块的值
new_l.alloc.construct(new_l.data, e);
uninitialized_copy(l.data, l.avail, new_l.data + 1);
return new_l;
}

//得到当前data指针所指向的元素的值
template <class T> T car(const list<T>& l) {
if (is_null(l))
return T();
return l.data[0];
}

//删除data指针指向的元素
template <class T> list<T> cdr(const list<T>& l) {
if (is_null(l))
return list<T>();
list<T> new_l;
//这里如果不注意,很容易出现无效的空指针错误
if (length(l) == 1) {
new_l.resize(length(l));
uninitialized_copy(l.data, l.avail, new_l.data);
return list<T>();
}
new_l.resize(length(l) - 1);
uninitialized_copy(l.data + 1, l.avail, new_l.data);
return new_l;
}

template <class T> size_t length(const list<T>& l) {
return l.avail - l.data;
}

//**************************** Other functions *********************************//
template <class T> bool is_null(const list<T>& l) {
return (length(l) == 0);
}

template <class T> T list_ref(const list<T>& l, size_t i) {
if (i == 0)
return car(l);
return list_ref(cdr(l), i - 1);
}

//将l1和l2连接为一个list
template <class T> list<T> app_helper(const list<T>& l1, const list<T>& l2) {
if (is_null(l1))
return l2;
list<T> new_l2 = cons(car(l1), l2);
return app_helper(cdr(l1), new_l2);
}

template <class T> list<T> append(const list<T>& l1, const list<T>& l2) {
return app_helper(reverse(l1), l2);
}

template <class T> list<T> rev_helper(const list<T>& l1, const list<T>& l2) {
if (is_null(l1))
return l2;
return rev_helper(cdr(l1), cons(car(l1), l2));//出现无效指针的问题
}

//逆函数
template <class T> list<T> reverse(const list<T>& l) {
return rev_helper(l, list<T>());
}

//
template <class T> list<T> member(const T& e, const list<T>& l) {
if (is_null(l))
return list<T>();
if (e == car(l))
return l;
return member(e, cdr(l));
}

//打印list中的元素
template <class T> void print(std::ostream& out, const list<T>& l) {
if (is_null(l))
return;
out << car(l) << " ";
print(out, cdr(l));
}

//定义运算符<<的动作
template <class T> std::ostream& operator<<(std::ostream& out, const list<T>& l) {
out << "( ";
print(out, l);
out << ")";
return out;
}


List_main.cpp

#include <iostream>
#include <conio.h>

#include "List.h"

using namespace std;

int main() {
list<int> l0 = list<int>();
int a1[] = {1, 2};
list<int> l1 = list<int>(a1, a1 + 2);
int a2[] = {3, 4};
list<int> l2 = list<int>(a2, a2 + 2);
list<int> l3;
l3 = append(l1, l2);

cout << l0 << endl;
cout << is_null(l0) << endl;
cout << l1 << endl;
cout << list_ref(l1, 0) << endl;
cout << list_ref(l1, 1) << endl;
cout << l3 << endl;
cout << reverse(l3) << endl;
cout << member<int>(2, l3) << endl;
cout << member<int>(0, l3) << endl;

cout << cons(l1, cons(l2, list< list<int> >())) << endl;

getch();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: