文章目录
- 1 编译运行讨论的程序
- 2 为什么第九章的Student_info结构中没有定义复制构造函数,也没有定义赋值运算符函数或析构函数?
- 2 为什么该结构中还没有定义一个默认构造函数?
- 3 Student_info的对象在自带调用生成的赋值操作函数具体执行了那些操作?
- 4 Student_info中的自动生成的析构函数删除了多少成员变量?
- 5 在Student_info类中加入计数代码,计算对象被创建、复制、赋值或删除的次数。用这个可以计数的类运行第6章的学生成绩程序。估计出这些不同的类对资源的消耗量。
- 6 在Vec类中增加一个删除其中一个元素的操作
- 7 使用Vec重写第九章的Student_info程序和第五章的字符串处理程序
- 8 写一个list类以及它相关的迭代器写一个简化版本
- 9 测试Vec中grow的分配方法对工作效率的提高
1 编译运行讨论的程序
#include <iostream>
#include <cstddef>
#include <memory>
#include <algorithm>
using std::cout;
using std::cin;
using std::endl;
using std::allocator;
using std::max;
using std::uninitialized_fill;
using std::uninitialized_copy;
using std::sort;
template<class T> class Vec{
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;
//构造函数
Vec(){create();}
//可以显示的给val值,也可以使用T的默认构造函数来生成这个值
explicit Vec(std::size_t n, const T& val = T()){create(n, val);}
//索引(返回引用,是为了避免容器的对象非常大时对它进行复制)
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 limit - data;}//容器长度
//返回迭代器类型
iterator begin(){ return data;}//读写
const_iterator begin() const { return data;}//只读
iterator end() { return avail;}
const_iterator end() const { return avail;}
//复制构造函数
Vec(const Vec& v) { create(v.begin(), v.end());}
//赋值运算符
Vec& operator=(const Vec&);//允许忽略具体类型的名称(因此没有显示声明返回类型名称)
//析构函数
~Vec(){ uncreate();}
private:
iterator data;//指针指向Vec的第一个元素
iterator avail;//指针指向构造元素后面的一个元素
iterator limit;//指针指向最后一个可获得元素后面的一个元素
//内存分配工具
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&);
};
//赋值运算符
template<class T> Vec<T>& Vec<T>::operator=(const Vec& rhs){
if(&rhs != this){//this:指向操作数对象的指针
//删除运算符左侧的数组
uncreate();
//从右侧复制元素到左侧
create(rhs.begin(), rhs.end());
}
//返回一个指向表达式做操作数对象的一个引用调用
//该对象生存周期大于赋值操作
//保证了函数返回的时候不被删除
return *this;//返回指向的对象
}
//默认构造
template<class T> void Vec<T>::create() {
data = avail = limit = 0;
}
//带一个参数大小和给初值
template<class T> void Vec<T>::create(size_type n, const T& val){
data = alloc.allocate(n);
limit = avail = data + n;
uninitialized_fill(data, limit, val);
}
//带参数大小
template<class T> void Vec<T>::create(const_iterator i, const_iterator j){
data = alloc.allocate(j - i);
limit = avail = uninitialized_copy(i, j, data);
}
//删除对象,释放占用的内存
template<class T> void Vec<T>::uncreate(){
//alloc.deallocate函数需要一个非零指针作为参数
//既是它不准备释放任何内存
if(data){
//以相反顺序构造函数生成的元素
iterator it = avail;
while(it != data){//删除对象
alloc.destroy(--it);
}
//返回占用的所有内存空间
alloc.deallocate(data, limit - data);//删除未初始化内存
}
//重置指针以表明Vec类型对象为空
data = limit = avail = 0;
}
//push_back函数的成员函数
template<class T> void Vec<T>::grow(){
//扩展对象大小时,为对象分配实际使用的两倍大小的内存空间
size_type new_size = max(2 * (limit - data), ptrdiff_t(1));//Vec为空的时候,选择一个元素进行分配
//分配新的内存空间并将已存在的对象元素内容复制搭配新内存中
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;
}
//假设avail指向一片新分配的但尚未初始化的内存空间
template<class T> void Vec<T>::unchecked_append(const T& val){
alloc.construct(avail++, val);
}
//找最大值
int max_Vec(Vec<int> vec){
sort(vec.begin(), vec.end());
return vec[vec.size() - 1];
}
Vec<int> sort_Vec(Vec<int> vec){
sort(vec.begin(), vec.end());
return vec;
}
int main(int argc, char** argv){
//测构造函数
Vec<int> v;//默认构造
Vec<int> v2(4);//带一个大小参数
Vec<int> v3(4,6);//带一个大小参数和初值
//cout << v3.size() << endl;
// for (Vec<int>::size_type j = 0; j != v3.size(); ++j) {//测索引
// cout << v3[j] <<" ";
// }
//测复制构造函数
v.push_back(3);//测push_back
v.push_back(1);
v.push_back(10);
v.push_back(7);
//隐式复制操作
// int d = max_Vec(v);//将vi作为参数传递给max_Vac函数
// cout << d;
// Vec<int> v4 = sort_Vec(v);//将sort_Vec函数的返回值赋给v4 //初始化
// for (Vec<int>::size_type j = 0; j != v4.size(); ++j) {
// cout << v4[j] <<" ";
// }
//显示复制
// Vec<int> v5 = v3;
// for (Vec<int>::size_type j = 0; j != v5.size(); ++j) {
// cout << v5[j] <<" ";
// }
//赋值
Vec<int> v4 = sort_Vec(v);//初始化
v3 = v4;//赋值操作,已存在的值擦去,以新值代替
for (Vec<int>::size_type j = 0; j != v3.size(); ++j) {
cout << v3[j] <<" ";
}
return 0;
}
2 为什么第九章的Student_info结构中没有定义复制构造函数,也没有定义赋值运算符函数或析构函数?
class Student_info{
public:
Student_info();//构造一个空的Student_info对象
Student_info(std::istream&);//读一个流从而构造一个对象
bool vaild() const{ return ! homework.empty();}//检查对象是否为空
double grade() const;
std::istream& read(std::istream& );
std::string name() const {return n;}//存取器:容许对一部分数据结构的进行访问
private:
std::string n;
double midterm, final;
std::vector<double> homework;
};
因为第九章的Student_info结构没有进行资源管理(如动态分配内存等),因此没有必要专门去写一个析构函数去释放分配的内存,系统会为我们生成相应的默认版本,进行默认操作。
对于这三个函数,因为在类中没有显示地定义这些操作,编译器会自动为类生成相应的默认版本的函数,进行一些默认的操作。
这些默认的函数被定义成一系列的递归操作。
- 对每个成员数据按照它们相应的类型进行复制、赋值或者删除,如果成员变量是类的对象实例,那么对它们进行复制、赋值与删除时会调用相应类的构造函数、赋值运算符函数或析构函数等。
- 如果成员变量为C++自带的变量类型,那么在对它们进行复制或赋值时将对它们的值进行复制或复制,而这类变量在删除时不需要任何额外的工作,其他变量类型是指针也不例外。
- 注意:通过默认析构函数删除一个指针变量时,不会释放指针指向的对象占用的内存空间。
2 为什么该结构中还没有定义一个默认构造函数?
因此类的每个数据成员都有自己的默认构造函数。
3 Student_info的对象在自带调用生成的赋值操作函数具体执行了那些操作?
首先删除一个已经存在的值(运算符左侧对象)然后用一个新值(运算符右侧对象)代替。
4 Student_info中的自动生成的析构函数删除了多少成员变量?
private:
std::string n;
double midterm, final;
std::vector<double> homework;
删除了4个成员变量。
5 在Student_info类中加入计数代码,计算对象被创建、复制、赋值或删除的次数。用这个可以计数的类运行第6章的学生成绩程序。估计出这些不同的类对资源的消耗量。
#ifndef ACM_Student_info
#define ACM_Student_info
#include <string>
#include <vector>
#include <iostream>
class Student_info{
public:
//构造函数
Student_info();//默认构造
Student_info(std::istream&);//输入流构造
Student_info(const Student_info&);//复制构造
//赋值运算符
Student_info& operator=(const Student_info&);
//析构函数
~Student_info();
std::istream& read(std::istream&);
double grade() const;
std::string name() const {return n;}
bool vail() const {return ! homework.empty();}
static void reset_count();
static std::ostream& print_cout(std::ostream&);
private:
std::string n;
double midterm, final;
std::vector<double> homework;
static int default_constructor_calls;//默认构造
static int stream_constructor_calls;//输入流构造
static int copy_constructor_calls;//复制构造
static int assignment_calls;//赋值运算符
static int destructor_calls;//析构函数
};
istream& read_hw(istream& , vector<double>& );
double grade(double , double ,const vector<double>& );
double grade(double, double, double);
double median(vector<double >);
#endif
#include <iostream>
using std::cin; using std::cout;
using std::endl; using std::istream;
using std::ostream;
#include <string>
using std::string;
#include <vector>
using std::vector;
#include <stdexcept>
using std::domain_error;
#include <algorithm>
using std::sort;
using std::stable_partition;
#include <chrono>
using std::chrono::steady_clock;
#include <fstream>
using std::ifstream;
#include <sstream>
using std::stringstream;
#include "Student_info.h"
int Student_info::default_constructor_calls;//默认构造
int Student_info::stream_constructor_calls;//输入流构造
int Student_info::copy_constructor_calls;//复制构造
int Student_info::assignment_calls;//赋值运算符
int Student_info::destructor_calls;//析构函数
//构造函数
Student_info::Student_info():midterm(0),final(0) {
++default_constructor_calls;
}
Student_info::Student_info(std::istream& is) {
++stream_constructor_calls;
read(is);
}
Student_info::Student_info(const Student_info &s) {
++copy_constructor_calls;
n = s.n;
midterm = s.midterm;
final = s.final;
homework = s.homework;
}
//赋值运算符
Student_info& Student_info::operator=(const Student_info &s) {
++assignment_calls;
if(&s != this){
n = s.n;
midterm = s.midterm;
final = s.final;
homework = s.homework;
}
return *this;
}
//析构函数
Student_info::~Student_info() {
++destructor_calls;
}
void Student_info::reset_count() {
default_constructor_calls = 0;
copy_constructor_calls = 0;
assignment_calls = 0;
stream_constructor_calls = 0;
destructor_calls = 0;
}
ostream& Student_info::print_cout(std::ostream &os) {
os << "default_constructor_calls: " << default_constructor_calls <<endl;
os << "stream_constructor_calls: " << stream_constructor_calls <<endl;
os << "copy_constructor_calls: " << copy_constructor_calls << endl;
os << "assignment_calls: " << assignment_calls <<endl;
os << "destructor_calls: " << destructor_calls <<endl;
return os;
}
istream& Student_info::read(istream& in){
in >> n >> midterm >> final;
read_hw(in, homework);
return in;
}
double Student_info::grade() const{
return ::grade(midterm, final, homework);
}
istream& read_hw(istream& in, vector<double>& hw){
if(in){
hw.clear();
double x;
while(in >> x){
hw.push_back(x);
}
in.clear();
}
return in;
}
double grade(double midterm, double final, const vector<double>& hw){
if(hw.size() == 0){
throw domain_error("Student has done no homework!");
}
return grade(midterm, final, median(hw));
}
double grade(double midterm, double final, double hw){
return midterm*0.2 + final*0.4 + hw*0.4;
}
double median(vector<double > vec){
typedef vector<double >::size_type v_sz;
v_sz size = vec.size();
if(size == 0){
throw domain_error("Median of an empty vector!");
}
sort(vec.begin(), vec.end());
v_sz mid = size/2;
return size % 2 == 0? (vec[mid] + vec[mid -1])/2 :vec[mid];
}
bool fgrade(const Student_info& s){
return s.grade() < 60;
}
bool pgrade(const Student_info& s){
return !fgrade(s);
}
vector<Student_info> extract_fails(vector<Student_info>& students)
{
vector<Student_info>::iterator iter = stable_partition(students.begin(),students.end(),pgrade);
vector<Student_info> fail(iter, students.end());
students.erase(iter, students.end());
return fail;
}
istream& read(istream& is, vector<Student_info>& v){
const int BUFFSIZE = 80;
stringstream ss;
char buff[BUFFSIZE];
while(is.getline(buff, BUFFSIZE)){
ss << buff;
Student_info students(ss);
v.push_back(students);
}
return is;
}
vector<Student_info> test_Student_info(string file, vector<Student_info>& s){
ifstream infile(file);
vector<Student_info> fails;
// infile.open(file);
steady_clock::time_point begin = std::chrono::steady_clock::now();
read(infile, s);
steady_clock::time_point end = std::chrono::steady_clock::now();
cout << "Microseconds to read " << file << " into vector = " << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() << endl;
Student_info::print_cout(cout);
infile.close();
infile.clear();
Student_info::reset_count();
begin = std::chrono::steady_clock::now();
fails = extract_fails(s);
end = std::chrono::steady_clock::now();
cout << "Microseconds to read " << file << " student vector = " <<std::chrono::duration_cast<std::chrono::microseconds>(end-begin).count() <<endl;
Student_info::print_cout(cout);
return fails;
}
void test(string file){
vector<Student_info> students_v;
test_Student_info(file, students_v);
}
int main(int argc, char ** argv){
// test("/Users/macbookpro/CLionProjects/ACM/students1000.txt");
ifstream infile("/Users/macbookpro/CLionProjects/ACM/students10.txt");
// vector<Student_info> s;
// read(infile, s);
// infile.close();
// infile.clear();
//测复制构造准备
// Student_info record(infile);
// infile.close();
// infile.clear();
//测赋值运算符准备
// Student_info record(infile);
// infile.close();
// infile.clear();
// Student_info record2(infile);
// infile.close();
// infile.clear();
//测析构函数
Student_info record(infile);
vector<Student_info> v;
v.push_back(record);
//测10次取中位数
//单次
//默认构造:10ms
//输入流构造:57ms
//复制构造:2ms
//赋值运算符:2ms
//析构函数:2ms
Student_info::reset_count();
steady_clock::time_point begin = std::chrono::steady_clock::now();
// Student_info record;//测默认构造
// Student_info record(infile);//测输入流构造
// Student_info record2 = record;//测复制构造
// record2 = record;//测赋值运算符
v.pop_back();//测析构函数
steady_clock::time_point end = std::chrono::steady_clock::now();
cout << "Microseconds to read into vector = " << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() << endl;
Student_info::print_cout(cout);
//测
return 0;
}
6 在Vec类中增加一个删除其中一个元素的操作
#include <iostream>
#include <cstddef>
#include <memory>
#include <algorithm>
using std::cout;
using std::cin;
using std::endl;
using std::allocator;
using std::max;
using std::uninitialized_fill;
using std::uninitialized_copy;
using std::sort;
using std::ostream;
template<class T> class Vec{
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;
//构造函数
Vec(){create();}
//可以显示的给val值,也可以使用T的默认构造函数来生成这个值
explicit Vec(std::size_t n, const T& val = T()){create(n, val);}
//复制构造函数
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);
}
//清空
void clear(){
destory();
}
//删除
void erase(iterator pos){
destory(pos);
}
void erase(iterator b , iterator e){
destory(b, e);
}
//打印数组
std::ostream& print_vec(std::ostream&);
//容器长度
size_type size() const { return limit - data;}//容器长度
//返回迭代器类型
iterator begin(){ return data;}//读写
const_iterator begin() const { return data;}//只读
iterator end() { return avail;}
const_iterator end() const { return avail;}
private:
iterator data;//指针指向Vec的第一个元素
iterator avail;//指针指向构造元素后面的一个元素
iterator limit;//指针指向最后一个可获得元素后面的一个元素
//内存分配工具
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&);
//支持clear函数
void destory();
//支持erase函数
iterator destory(iterator);
iterator destory(iterator, iterator);
};
//赋值运算符
template<class T> Vec<T>& Vec<T>::operator=(const Vec& rhs){
if(&rhs != this){//this:指向操作数对象的指针
//删除运算符左侧的数组
uncreate();
//从右侧复制元素到左侧
create(rhs.begin(), rhs.end());
}
//返回一个指向表达式做操作数对象的一个引用调用
//该对象生存周期大于赋值操作
//保证了函数返回的时候不被删除
return *this;//返回指向的对象
}
//默认构造
template<class T> void Vec<T>::create() {
data = avail = limit = 0;
}
//带一个参数大小和给初值
template<class T> void Vec<T>::create(size_type n, const T& val){
data = alloc.allocate(n);
limit = avail = data + n;
uninitialized_fill(data, limit, val);
}
//带参数大小
template<class T> void Vec<T>::create(const_iterator i, const_iterator j){
data = alloc.allocate(j - i);
limit = avail = uninitialized_copy(i, j, data);
}
//删除对象,释放占用的内存
template<class T> void Vec<T>::uncreate(){
//alloc.deallocate函数需要一个非零指针作为参数
//既是它不准备释放任何内存
if(data){
//以相反顺序构造函数生成的元素
iterator it = avail;
while(it != data){//删除对象
alloc.destroy(--it);
}
//返回占用的所有内存空间
alloc.deallocate(data, limit - data);//删除未初始化内存
}
//重置指针以表明Vec类型对象为空
data = limit = avail = 0;
}
//push_back函数的成员函数
template<class T> void Vec<T>::grow(){
//扩展对象大小时,为对象分配实际使用的两倍大小的内存空间
size_type new_size = max(2 * (limit - data), ptrdiff_t(1));//Vec为空的时候,选择一个元素进行分配
//分配新的内存空间并将已存在的对象元素内容复制搭配新内存中
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;
}
//假设avail指向一片新分配的但尚未初始化的内存空间
template<class T> void Vec<T>::unchecked_append(const T& val){
alloc.construct(avail++, val);
}
template <class T>
void Vec<T>::destory() {
iterator it = avail;
while(it != data){
alloc.destroy(--it);
}
avail = data;
}
template <class T>
typename Vec<T>::iterator Vec<T>::destory(Vec::iterator pos) {
if(data && pos != avail){
alloc.destroy(pos);
iterator it = pos + 1;
while(it != avail){
alloc.construct(pos++, *it++);
alloc.destroy(pos);
}
avail = pos;
}
return avail;
}
template <class T>
typename Vec<T>::iterator Vec<T>::destory(Vec<T>::iterator b, Vec<T>::iterator e) {
if(data && b != avail && b != e){
iterator it = b;
while(it != e){
alloc.destroy(it);
}
while(e != avail){
alloc.construct(b++, *e);
alloc.destroy(e++);
}
avail = b;
}
return avail;
}
template<class T>
ostream& Vec<T>::print_vec(std::ostream &os) {
if(avail - data > 0){
const_iterator iter = data;
os << *iter++;
while(iter != avail){
os << " " << *iter++;
}
os << std::endl;
}
return os;
}
//找最大值
int max_Vec(Vec<int> vec){
sort(vec.begin(), vec.end());
return vec[vec.size() - 1];
}
Vec<int> sort_Vec(Vec<int> vec){
sort(vec.begin(), vec.end());
return vec;
}
int main(int argc, char** argv){
//测构造函数
Vec<int> v;//默认构造
// Vec<int> v2(4);//带一个大小参数
// Vec<int> v3(4,6);//带一个大小参数和初值
//cout << v3.size() << endl;
// for (Vec<int>::size_type j = 0; j != v3.size(); ++j) {//测索引
// cout << v3[j] <<" ";
// }
//测复制构造函数
// v.push_back(3);//测push_back
// v.push_back(1);
// v.push_back(10);
// v.push_back(7);
//隐式复制操作
// int d = max_Vec(v);//将vi作为参数传递给max_Vac函数
// cout << d;
// Vec<int> v4 = sort_Vec(v);//将sort_Vec函数的返回值赋给v4 //初始化
// for (Vec<int>::size_type j = 0; j != v4.size(); ++j) {
// cout << v4[j] <<" ";
// }
//显示复制
// Vec<int> v5 = v3;
// for (Vec<int>::size_type j = 0; j != v5.size(); ++j) {
// cout << v5[j] <<" ";
// }
//赋值
// Vec<int> v4 = v;//初始化
// v3 = v4;//赋值操作,已存在的值擦去,以新值代替
// for (Vec<int>::size_type j = 0; j != v3.size(); ++j) {
// cout << v3[j] <<" ";
// }
//测删除
v.push_back(1);//测push_back
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.erase(v.begin());
// v.clear();
v.print_vec(cout);
// for (Vec<int>::const_iterator it = v.begin(); it != v.end(); ++it) {
// cout << *it <<" ";
// }
return 0;
}
7 使用Vec重写第九章的Student_info程序和第五章的字符串处理程序
头文件:
#ifndef Vec_H
#define Vec_H
#include <iostream>
#include <cstddef>
#include <memory>
#include <algorithm>
template<class T> class Vec{
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;
//构造函数
Vec(){create();}
//可以显示的给val值,也可以使用T的默认构造函数来生成这个值
explicit Vec(std::size_t n, const T& val = T()){create(n, val);}
//复制构造函数
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);
}
//清空
void clear(){
destory();
}
//删除
void erase(iterator pos){
destory(pos);
}
void erase(iterator b , iterator e){
destory(b, e);
}
//出元素
void pop_back(){
pop();
}
//打印数组
std::ostream& print_vec(std::ostream&);
//判断空
bool empty() const{return !data;}
//容器长度
size_type size() const { return limit - data;}//容器长度
//返回迭代器类型
iterator begin(){ return data;}//读写
const_iterator begin() const { return data;}//只读
iterator end() { return avail;}
const_iterator end() const { return avail;}
private:
iterator data;//指针指向Vec的第一个元素
iterator avail;//指针指向构造元素后面的一个元素
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&);
//支持clear函数
void destory();
//支持erase函数
iterator destory(iterator);
iterator destory(iterator, iterator);
//支持pop_back
void pop();
};
//赋值运算符
template<class T> Vec<T>& Vec<T>::operator=(const Vec& rhs){
if(&rhs != this){//this:指向操作数对象的指针
//删除运算符左侧的数组
uncreate();
//从右侧复制元素到左侧
create(rhs.begin(), rhs.end());
}
//返回一个指向表达式做操作数对象的一个引用调用
//该对象生存周期大于赋值操作
//保证了函数返回的时候不被删除
return *this;//返回指向的对象
}
//默认构造
template<class T> void Vec<T>::create() {
data = avail = limit = 0;
}
//带一个参数大小和给初值
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);
}
//带参数大小
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(){
//alloc.deallocate函数需要一个非零指针作为参数
//既是它不准备释放任何内存
if(data){
//以相反顺序构造函数生成的元素
iterator it = avail;
while(it != data){//删除对象
alloc.destroy(--it);
}
//返回占用的所有内存空间
alloc.deallocate(data, limit - data);//删除未初始化内存
}
//重置指针以表明Vec类型对象为空
data = limit = avail = 0;
}
//push_back函数的成员函数
template<class T> void Vec<T>::grow(){
//扩展对象大小时,为对象分配实际使用的两倍大小的内存空间
size_type new_size = std::max(2 * (limit - data), ptrdiff_t(1));//Vec为空的时候,选择一个元素进行分配
//分配新的内存空间并将已存在的对象元素内容复制搭配新内存中
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;
}
//假设avail指向一片新分配的但尚未初始化的内存空间
template<class T> void Vec<T>::unchecked_append(const T& val){
alloc.construct(avail++, val);
}
template <class T>
void Vec<T>::destory() {
iterator it = avail;
while(it != data){
alloc.destroy(--it);
}
avail = data;
}
template <class T>
typename Vec<T>::iterator Vec<T>::destory(Vec::iterator pos) {
if(data && pos < avail && pos >= data){
alloc.destroy(pos);
iterator it = pos +1;
while(it != avail){
alloc.construct(pos++, *it++);
alloc.destroy(pos);
}
avail = pos;
}
return avail;
}
template <class T>
typename Vec<T>::iterator Vec<T>::destory(Vec<T>::iterator b, Vec<T>::iterator e) {
if(data && b < e && e < avail && b >= data){
iterator it = b;
while(it != e){
alloc.destroy(it++);
}
while(e != avail){
alloc.construct(b++, *e);
alloc.destroy(e++);
}
avail = b;
}
return avail;
}
template<class T>
std::ostream& Vec<T>::print_vec(std::ostream &os) {
if(avail - data > 0){
const_iterator iter = data;
os << *iter++;
while(iter != avail){
os << " " << *iter++;
}
os << std::endl;
}
return os;
}
template <class T>
void Vec<T>::pop() {
if(data){
alloc.destroy(--avail);
}
}
#endif
重写第九章程序
//
// tudent_info.h
//
#ifndef ACM_Student_info
#define ACM_Student_info
#include <iostream>
#include <string>
#include <vector>
#include "Vec.h"
//struct student_info{
// std::string name;
// double midterm, final;
// std::vector<double> homework;
//
// std::istream& read(std::istream&);
// double garde() const;
//};
class Student_info{
public:
Student_info();//构造一个空的Student_info对象
Student_info(std::istream&);//读一个流从而构造一个对象
bool vaild() const{ return ! homework.empty();}//检查对象是否为空
double grade() const;
std::istream& read(std::istream& );
std::string name() const {return n;}//存取器:容许对一部分数据结构的进行访问
private:
std::string n;
double midterm, final;
Vec<double> homework;
};
bool compare(const Student_info&, const Student_info&);
std::istream& read_hw(std::istream&, Vec<double>&);
double grade(double, double, double);
double grade(double, double, const Vec<double>&);
#endif
#include <iostream>
#include <string>
#include <vector>
#include <string>
#include <algorithm>
#include <stdexcept>
#include <iomanip>
#include <ios>
#include "Student_info.h"
#include "Vec.h"
using std::cin; using std::cout;
using std::endl;
using std::istream;
using std::vector;
using std::string;
using std::max;
using std::sort;
using std::domain_error;
using std::setprecision;
using std::streamsize;
//默认构造函数
Student_info::Student_info() :midterm(0), final(0){ }
//带参构造函数
Student_info::Student_info(istream& is) { read(is); }
bool compare(const Student_info& x, const Student_info& y){
return x.name() < y.name();
}
istream& Student_info::read(istream& in){
in >> n >> midterm >> final;
read_hw(in, homework);
return in;
}
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;
}
double median(Vec<double> vec){
typedef Vec<double>::size_type vec_sz;
vec_sz size = vec.size();
if(size == 0){
throw domain_error("median of an empty vector");
}
sort(vec.begin(), vec.end());
vec_sz mid = size/2;
return size % 2 == 0 ? (vec[mid] + vec[mid -1]) /2 : vec[mid];
}
double Student_info::grade() const {
//::使用这个名称的某一个版本,而所使用的这个版本不能称为任何事物的成员
return ::grade(midterm, final, homework);
}
double grade(double midterm, double final, const Vec<double>& hw){
if(hw.size() == 0)
throw domain_error("student has done no homework");
return grade(midterm, final, median(hw));//如果家庭作业非空,则调用grade3
}//grade2
double grade(double midterm, double final, double hw){
return midterm * 0.2 + final * 0.4 + hw * 0.4;
}
int main(int argc, char const *argv[]){
Vec<Student_info> students;
Student_info record;
string::size_type maxlen = 0;
while(record.read(cin)){//
maxlen = max(maxlen, record.name().size());//
students.push_back(record);
}
sort(students.begin(), students.end(), compare);
for (Vec<Student_info>::size_type i = 0; i != students.size(); ++i) {
cout << students[i].name()//
<<string(maxlen + 1 - students[i].name().size(), ' ');
// try{
// double final_grade = students[i].grade();
// streamsize prec = cout.precision();
// cout << setprecision(3) << final_grade
// << setprecision(prec) << endl;
// }catch(domain_error e){
// cout << e.what() << endl;
// }
if(students[i].vaild() == true){
double final_grade = students[i].grade();
streamsize prec = cout.precision();
cout << setprecision(3) << final_grade
<< setprecision(prec) << endl;
}else{
cout << "homework is empty!"<< endl;
}
}
return 0;
}
重写第五章:
#include <iostream>
#include <string>
#include "Vec.h"
#include <list>
#include <algorithm>
#include <cctype>
using std::cin; using std::endl;
using std::cout; using std::string;
using std::max;
//分割字符串
Vec<string> split(const string& s){
Vec<string> ret;
typedef string::size_type string_size;
string_size i = 0;
while(i != s.size()){
//忽略前段的空白:[先前的i,i)中全部字符都是空格
while(i != s.size() && isspace(s[i])){
i++;
}
//找出下一个单词的终结点
string_size j = i;
//[先前的j,j)中的任意字符都不是空格
while(j != s.size() && !isspace(s[j])){
j++;
}
//找到了一些非空白符
if(i != j){
ret.push_back(s.substr(i, j - i));
i = j;
}
}
return ret;
}
//找出向量中最长字符串的长度
string::size_type width(const Vec<string>& v){
string::size_type maxlen = 0;
for (Vec<string>::size_type i = 0; i != v.size(); ++i) {
maxlen = max(maxlen, v[i].size());
}
return maxlen;
}
Vec<string> frame(const Vec<string>& v){
Vec<string> ret;
string::size_type maxlen = width(v);
//输出顶部边框
string border(maxlen + 4, '*');
//输出内部的行,每行都用一个星号和一个空格来框起来
ret.push_back(border);
for (Vec<string>::size_type i = 0; i != v.size(); ++i) {
ret.push_back("* "+ v[i] + string(maxlen - v[i].size(), ' ') + " *");
}
//输出底部边框
ret.push_back(border);
return ret;
}
//纵向连接
Vec<string> vcat(const Vec<string>& top, const Vec<string>& bottom){
Vec<string> ret = top;
for (Vec<string>::const_iterator it = bottom.begin(); it != bottom.end() ; ++it) {
ret.push_back(*it);
}
//作用同上
// ret.insert(ret.end(), bottom.begin(), bottom.end());
return ret;
}
//横向连接
Vec<string> hcat(const Vec<string>& left, const Vec<string>& right){
Vec<string>ret;
//在两幅图案之间留空格
string::size_type width1 = width(left) + 1;
//用于遍历left和right的索引
Vec<string>::size_type i = 0, j = 0;
while(i != left.size() || j != right.size()){
string s;
//如果左侧图案还有待复制的行,则复制一行
if(i != left.size()){
s = left[i++];
}
//填充至适当长度
s += string(width1 - s.size(), ' ');
//如果右侧还有代复制的行,则复制一行
if(j != right.size()){
s += right[j++];
}
ret.push_back(s);
}
return ret;
}
int main(int argc,const char *argv[]){
string s;
while(getline(cin, s)){
Vec<string> v = split(s);
// for (vector<string>::size_type i = 0; i != v.size(); ++i) {
// cout << v[i] <<endl;
// }
Vec<string> fra = frame(v);
Vec<string> col, row;
col = vcat(v, fra);
row = hcat(v, fra);
//打印竖着拼图
for (Vec<string>::size_type i = 0; i != col.size(); ++i) {
cout << col[i] << endl;
}
// //打印横向拼图
for (Vec<string>::size_type j = 0; j != row.size(); ++j) {
cout << row[j] <<endl;
}
}
return 0;
}
8 写一个list类以及它相关的迭代器写一个简化版本
头文件:list.h
#ifndef List_H
#define List_H
#include <memory>
template <class T>
struct Node
{
T data;
Node<T>* previous;
Node<T>* next;
Node() : data(0), previous(0), next(0) {};
Node(T d) : data(d), previous(0), next(0) {};
};
template <class T>
class NodeIterator
{
public:
NodeIterator(Node<T>* d) : data(d) {};
NodeIterator& operator++();
NodeIterator& operator--();
NodeIterator operator++(int);
NodeIterator operator--(int);
bool operator!=(NodeIterator&) const;
T& operator*() const;
private:
Node<T>* data;
};
template <class T>
NodeIterator<T>& NodeIterator<T>::operator++()
{
data = data->next;
return *this;
}
template <class T>
NodeIterator<T>& NodeIterator<T>::operator--()
{
data = data->previous;
return *this;
}
template <class T>
NodeIterator<T> NodeIterator<T>::operator++(int)
{
NodeIterator<T> ret(this->data);
data = data->next;
return ret;
}
template <class T>
NodeIterator<T> NodeIterator<T>::operator--(int)
{
NodeIterator<T> ret(this->data);
data = data->previous;
return this;
}
template <class T>
bool NodeIterator<T>::operator!=(NodeIterator& rhs) const
{
return this->data != rhs.data;
}
template <class T>
T& NodeIterator<T>::operator*() const
{
return data->data;
}
template <class T>
class LList
{
public:
typedef NodeIterator<T> iterator;
typedef const NodeIterator<T> const_iterator;
typedef size_t size_type;
typedef T value_type;
LList() : front(0), back(0), s(0) {}
explicit LList(size_type s, const T& t = T()) { create(s, t); }
LList(const LList& l) { create(l.begin(), l.end()); }
LList& operator=(const LList&);
~LList() { uncreate(); }
void push_back(const T& t) {
append(t);
}
size_type size() const { return s; }
iterator begin() { return iterator(front); }
const_iterator begin() const { return iterator(front); }
iterator end() { return iterator(0); }
const_iterator end() const { return iterator(0); }
private:
Node<T>* front;
Node<T>* back;
size_type s;
std::allocator<Node<T>> alloc;
void create(size_type, const T&);
void create(iterator, iterator);
void append(const T&);
void uncreate();
};
template <class T>
LList<T>& LList<T>::operator=(const LList& l)
{
if (&l != this) {
uncreate();
create(l.begin(), l.end());
}
return *this;
}
template <class T>
void LList<T>::create(size_type s, const T& t)
{
for (size_type i = 0; i < s; i++)
append(t);
}
template <class T>
void LList<T>::create(iterator b, iterator e)
{
while (b != e)
append(*b++);
}
template <class T>
void LList<T>::append(const T& t)
{
Node<T>* node = new Node<T>(t);
if (s == 0)
front = node;
else if (s == 1)
{
node->previous = front;
back = node;
front->next = node;
}
else
{
back->next = node;
node->previous = back;
back = node;
}
s++;
}
template <class T>
void LList<T>::uncreate()
{
Node<T>* node = back;
while (node != 0)
{
Node<T>* node_delete = node;
node = node->previous;
delete node_delete;
}
front = back = 0;
s = 0;
}
#endif // List_H
测试:
/**
//#include "stdafx.h"//头文件预编译
#include "list.h"
#include <iostream>
using std::cout;
using std::endl;
#include <string>
using std::string;
int main()
{
LList<int> list;
list.push_back(5);
list.push_back(10);
list.push_back(15);
LList<int>::iterator iter = list.begin();
cout << *++iter << endl;
cout << *--iter << endl;
while (iter != list.end())
cout << *iter++ << endl;
LList<string> stringlist(5, "test");
LList<string> stringlist_copy = stringlist;
LList<string>::iterator listIter = stringlist.begin();
*listIter = "first";
while (listIter != stringlist.end())
cout << *listIter++ << endl;
if (stringlist_copy.size() > 0) {
listIter = stringlist_copy.begin();
while (listIter != stringlist.end())
cout << *listIter++ << endl;
}
return 0;
}
9 测试Vec中grow的分配方法对工作效率的提高
本次测试了三组数组:
插入10个元素:
多分配2倍的预分配空间方法:1ms
仅多分配一个的预分配空间方法:2ms
插入100个元素:
多分配2倍的预分配空间方法:4ms
仅多分配一个的预分配空间方法:55ms
插入1000个元素:
多分配2倍的预分配空间方法:24ms
仅多分配一个的预分配空间方法:3062ms
由此可见,预分配两倍内存的方案在插入的数据元素越多的情况下,效率越出众。
测试代码:
头文件:
#ifndef Vec_H
#define Vec_H
#include <iostream>
#include <cstddef>
#include <memory>
#include <algorithm>
template<class T> class Vec{
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;
//构造函数
Vec(){create();}
//可以显示的给val值,也可以使用T的默认构造函数来生成这个值
explicit Vec(std::size_t n, const T& val = T()){create(n, val);}
//复制构造函数
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, bool double_grow = true){
if(avail == limit){
grow(double_grow);
}
unchecked_append(t);
}
//清空
void clear(){
destory();
}
//删除
void erase(iterator pos){
destory(pos);
}
void erase(iterator b , iterator e){
destory(b, e);
}
//出元素
void pop_back(){
pop();
}
//打印数组
std::ostream& print_vec(std::ostream&);
//判断空
bool empty() const{return !data;}
//添加元素:
void insert(iterator it,const T& t){
std::ptrdiff_t dis = it - data;
if(avail == limit) grow(true);
add(dis, t);
}
void insert(iterator out, const_iterator b, const_iterator e){
std::ptrdiff_t start = out - data;
std::ptrdiff_t dis = e - b;
if(dis > 0){//插入区间合法
while(out + dis >= limit){
grow();
out = data + start;//重新更新out
}
add(start,b, e);
}
}
//容器长度
size_type size() const { return limit - data;}//容器长度
//返回迭代器类型
iterator begin(){ return data;}//读写
const_iterator begin() const { return data;}//只读
iterator end() { return avail;}
const_iterator end() const { return avail;}
private:
iterator data;//指针指向Vec的第一个元素
iterator avail;//指针指向构造元素后面的一个元素
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(bool);
void unchecked_append(const T&);
//支持clear函数
void destory();
//支持erase函数
iterator destory(iterator);
iterator destory(iterator, iterator);
//支持pop_back
void pop();
//支持insert
void add(std::ptrdiff_t,const T&);
void add(std::ptrdiff_t, const_iterator, const_iterator);
};
//赋值运算符
template<class T> Vec<T>& Vec<T>::operator=(const Vec& rhs){
if(&rhs != this){//this:指向操作数对象的指针
//删除运算符左侧的数组
uncreate();
//从右侧复制元素到左侧
create(rhs.begin(), rhs.end());
}
//返回一个指向表达式做操作数对象的一个引用调用
//该对象生存周期大于赋值操作
//保证了函数返回的时候不被删除
return *this;//返回指向的对象
}
//默认构造
template<class T> void Vec<T>::create() {
data = avail = limit = 0;
}
//带一个参数大小和给初值
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);
}
//带参数大小
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(){
//alloc.deallocate函数需要一个非零指针作为参数
//既是它不准备释放任何内存
if(data){
//以相反顺序构造函数生成的元素
iterator it = avail;
while(it != data){//删除对象
alloc.destroy(--it);
}
//返回占用的所有内存空间
alloc.deallocate(data, limit - data);//删除未初始化内存
}
//重置指针以表明Vec类型对象为空
data = limit = avail = 0;
}
//push_back函数的成员函数
template<class T> void Vec<T>::grow(bool double_grow){
size_type new_size;
if(double_grow == true){
//扩展对象大小时,为对象分配实际使用的两倍大小的内存空间
//Vec为空的时候,选择一个元素进行分配
new_size = std::max(2 * (limit - data), std::ptrdiff_t(1));
}else{
new_size = limit - data + 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;
}
//假设avail指向一片新分配的但尚未初始化的内存空间
template<class T> void Vec<T>::unchecked_append(const T& val){
alloc.construct(avail++, val);
}
template <class T>
void Vec<T>::destory() {
iterator it = avail;
while(it != data){
alloc.destroy(--it);
}
avail = data;
}
template <class T>
typename Vec<T>::iterator Vec<T>::destory(Vec::iterator pos) {
if(data && pos < avail && pos >= data){
alloc.destroy(pos);
iterator it = pos +1;
while(it != avail){
alloc.construct(pos++, *it++);
alloc.destroy(pos);
}
avail = pos;
}
return avail;
}
template <class T>
typename Vec<T>::iterator Vec<T>::destory(Vec<T>::iterator b, Vec<T>::iterator e) {
if(data && b < e && e < avail && b >= data){
iterator it = b;
while(it != e){
alloc.destroy(it++);
}
while(e != avail){
alloc.construct(b++, *e);
alloc.destroy(e++);
}
avail = b;
}
return avail;
}
template<class T>
std::ostream& Vec<T>::print_vec(std::ostream &os) {
if(avail - data > 0){
const_iterator iter = data;
os << *iter++;
while(iter != avail){
os << " " << *iter++;
}
os << std::endl;
}
return os;
}
template <class T>
void Vec<T>::pop() {
if(data){
alloc.destroy(--avail);
}
}
template <class T>
void Vec<T>::add(std::ptrdiff_t dis, const T& val){
if(dis < avail - data){
iterator e = avail;
iterator b = avail -1;
while(e != data + dis){
alloc.construct(e--, *b--);
alloc.destroy(b);
}
alloc.construct(data + dis, val);
++avail;
}
}
template <class T>
void Vec<T>::add(std::ptrdiff_t start, Vec<T>::const_iterator b, Vec<T>::const_iterator e) {
iterator iter = data + start;
while(b != e){
*iter++ = *b++;
}
avail = iter;
}
#endif
测试函数:
#include <iostream>
#include "Vec.h"
#include <vector>
#include <chrono>
using std::vector;
using std::cin; using std::cout;
using std::endl;
using std::chrono::steady_clock;
void test_push_back(int num){
Vec<int> v1;
Vec<int> v2;
steady_clock::time_point begin = std::chrono::steady_clock::now();
for (int i = 0; i < num; ++i) {
v1.push_back(i);
}
steady_clock::time_point end = std::chrono::steady_clock::now();
cout << "Microseconds to add " << num << " to vector using double memory method ="
<< std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()<<endl;
begin = std::chrono::steady_clock::now();
for (int j = 0; j < num; ++j) {
v2.push_back(j, false);
}
end = std::chrono::steady_clock::now();
cout << "Microseconds to add " << num << " to vector without using double memory method ="
<< std::chrono::duration_cast<std::chrono::microseconds>(end-begin).count()<<endl;
}
int main(int argc, char const *argv[]){
//测新push_back
test_push_back(1000);
return 0;
}