本周课程老师讲解了各种容器的部分使用方法,并且对它们处理元素的速度做了测试,使学生对于各种容器的特点有了一些认识。还讲了STL的体系结构和分配器的使用。这些内容涉及的基础知识C++ Primer上面都有,还是那句话,我再抄一遍没意义,所以我把C++ Primer模板那一章的习题做了一些,这章的题除了涉及到模板,还整合了很多之前学习容器的时候的习题(往往是用模板实现类或者函数,其中有很多使用容器的练习)。能力有限,这一章的题我没有都写完,因为其中有些题目还是挺复杂的。我把目前写完的先记在这篇笔记里,没写完的和有疑问的我研究以后再写进来。
P583 E16.4
//find.h
//find.h
#pragma once
//模板参数规定了函数的c参数类型,模板参数的个数跟函数参数的个数无关
template<typename T, typename U>
T find( T& b, T& e, const U& value)
{
int sign = 1;
for (b; b != e; b++)
{
if (*b == value)
{
return b;
sign = -1;
}
}
if (!sign)
return e;
/*
//e是尾后迭代器,如果b的值累加到了e,说明已经遍历完毕容器,要找的元素不在此容器中
//这个while循环比我写的for循环更简洁,这样写才是懂了尾后迭代器
while (b != e)
b++;
return b;
*/
}
//find.cpp
#include"stdafx.h"
#include<iostream>
#include<vector>
#include<string>
#include<list>
#include "find.h"
using namespace std;
int main()
{
vector<int> vi{ 1, 2, 3 };
auto iter = find(vi.begin(), vi.end(), 4);
if (iter == vi.end())
cout << "Did not find 3." << endl;
else
cout << "Value i at position " << iter - vi.begin() << endl;
list<string> ls{ "hello", "world" };
auto iter2 = find(ls.begin(), ls.end(),"hello" );
if (iter2 == ls.end())
cout << "Did not find hello " << endl;
else
cout << "Found hello." << endl;
/*
//元素存储在连续内存空间里的容器,如vector,string,deque的迭代器是有加减法的
//但是map,set,multimap,multiset的迭代器是没有加减法的,list也没有
//所以下面的语句会报错,找不到匹配的运算符
cout << "Value i at position " << iter2 - ls.begin() << endl;
*/
system("pause");
return 0;
}
P583 E16.5
//print template.h
#pragma once
#include<iostream>
using std::cout;
template<typename T, typename U>
void print(const T& arr, const U& n)
{
arr[n];
for (auto elem: arr)
cout << elem << " ";
}
/*
//这个答案直接把print的参数写成数组,调用时传入数组名即可,更合理一点
//我的答案时模仿了书上传两个参数
//原本以为参数写成数组要写成这样
//template<typename T, typename U> void print(const T(&a)[U N])
//可是有很多错误,也许传数组引用只能用偏特化的模板来写吧
template<typename T, size_t N>
void print(const T(&a)[N])
{
for (auto elem : a)
cout << elem << " ";
}
*/
// P583 E16.5.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
//P583 E16.5.cpp
#include"print template.h"
int main()
{
const int n = 5;
int arr[n]{ 1, 2 };
print(arr, n);
return 0;
}
P583 E16.6
//end template.h
#pragma once
template<typename T, size_t N>
T myEnd(const T(&arr)[N])//返回类型前应该有const
{
size_t i = 0;
while (i != N - 1)
{
i++;
}
//标准库的begin和end应该返回指针
return arr[i];
}
/*
template<typename T, size_t N>
const T* my_end(const T(&arr)[N])
{
//移动指针得到指向尾元素的指针
return &a[0] + N;
}
*/
//begin template.h
#pragma once
template<typename T, size_t N>
T myBegin(const T(&arr)[N])////返回类型前应该有const
{
//标准库的begin和end应该返回指针
return arr[0];
}
/*
//答案里面begin和end分别返回了数组第一个和最后一个元素的指针
//对指针解引用即得到相应的元素
//返回类型前有const,我的没有,不好
template<typename T, size_t N>
const T* my_begin(const T(&a)[N])
{
return &a[0];
}
*/
//P583 E16.6.cpp
#include"end template.h"
#include<iostream>
using namespace std;
int main()
{
int arr[5]{0,1,2,3,4 };
cout << "The first element: " << myBegin(arr) << endl;
cout <<"The last element: " << myEnd(arr) << endl;
return 0;
}
P592 E16.12
//BlobPtr Template.h
#pragma once
#include"Blob Template.h"
#include <vector>
#include <memory>
#include <string>
using namespace std;
template<typename T>
class BlobPtr
{
public:
BlobPtr() : curr(0){}
BlobPtr(Blob<T>& a, size_t sz = 0):wptr(a.data), curr(sz){}
T& operator*() const;
BlobPtr& operator++();
BlobPtr& operator--();
private:
shared_ptr<vector<T>> check(size_t, const string&) const;
weak_ptr<vector<T>> wptr;
size_t curr;
};
template<typename T>
T& BlobPtr<T>::operator*() const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
//前缀递增:返回递增后的对象的引用
template<typename T>
BlobPtr<T>& BlobPtr<T>::operator++()
{
check(curr, "increment past end of BlobPtr");
++curr;
return *this;
}
//前缀递减:返回递减后的对象的引用
template<typename T>
BlobPtr<T>& BlobPtr<T>::operator--()
{
check(curr, "decrement past end of BlobPtr");
--curr;
return *this;
}
template<typename T>
shared_ptr<vector<T>> BlobPtr<T>::check(size_t sz, const string& msg) const
{
auto ret = wptr.lock();
//判断wptr指向的对象是否存在
//BlobPtr这个类存在的意义之一就是41,42这两行代码
//即防止用户访问不存在的容器对象(这里是vector)
if (!ret)
//学习抛出异常的表达式
throw runtime_error("unbound BlobPtr");
//sz是否小于wptr指向的vector的size
if (sz > ret->size())
//学习抛出异常的表达式
throw out_of_range(msg);
return ret;
}
//Blob Template
#pragma once
#include <vector>
#include <memory>
#include <string>
#include <initializer_list>
using namespace std;
template<typename> class BlobPtr;
template<typename> class Blob;
template<typename T> bool operator==(const Blob<T>& B1, const Blob<T>& B2)
{
return B1.data == B2.data;
}
template<typename T>
class Blob
{
friend class BlobPtr<T>;
friend bool operator==<T>(const Blob<T>&, const Blob<T>&);
public:
typedef T value_type;
typedef typename vector<T>::size_type size_type;
//使用编译器合成的拷贝,赋值和析构函数
Blob();
Blob(initializer_list<T> il);
size_type size() const { return data->size(); }
bool empty() const { return data->empty(); }
void push_back(const T& elem) { data->push_back(elem); }
//void push_back(const T& elem) { data->push_back(move(elem)); }
void pop_back();
T& back();
T& operator[] (size_type i);
//这两个函数我之前一直不懂,现在明白了一点
//这两个函数是Blob的成员函数,可以由Blob对象调用
//但是里面的操作是用BlobPtr做的
BlobPtr<T> begin() { return BlobPtr<T>(*this); }
BlobPtr<T> end() { return BlobPtr<T>(*this, data->size()); }
/*
//begin()和end()也可以写成下面这样
//P422 E12.20要求用StrBlobPtr打印StrBlob里的元素
//这个要求必须用上面的begin()和end(),加上for循环和deref()来实现
//但是如果只打印StrBlob里的元素,而不要求用StrBlobPtr
//下面的两个函数完全可以更简单地做到
T& my_begin() { return *data->begin(); }
T& my_end() { return *data->end(); }
*/
private:
shared_ptr<vector<T>> data;
void check(size_type i, const string& msg) const;
};
//类外记得加上模板参数<T>
template<typename T>
void Blob<T>::check(size_type i, const string& msg) const
{
if (i > data->size())
//用throw抛出异常,不用return
throw out_of_range(msg);
}
//make_shared()不传递任何参数,对象值初始化(P88)
//比如,vector里的类型(T)是int,就初始化为0;
//是string就按照string的默认函数初始化
template<typename T>
Blob<T>::Blob() :data(make_shared<vector<T>()) {}
//il初始化vector里的元素;
//make_shared得到的shared_ptr初始化数据成员data
template<typename T>
Blob<T>::Blob(initializer_list<T> il)
: data(make_shared<vector<T>>(il)) {}
/*
//两个构造函数都写错了
//构造函数用来初始化数据成员
//这个模板类应该用shared_ptr初始化shared_ptr
//构造一个shared_ptr的最好办法是使用make_shared()
template<typename T>
Blob<T>::Blob():data(nullptr){}
template<typename T>
Blob<T>::Blob(initializer_list<T> il)
{
//有办法写成初值列吗
for (auto elem : il)
data = elem;
}
*/
template<typename T>
void Blob<T>::pop_back()
{
check(0, "pop_back pon empty Blob");
data->pop_back();
}
template<typename T>
T& Blob<T>::back()
{
check(0, "back on empty Blob");
return data->back();
}
template<typename T>
T& Blob<T>::operator[] (size_type i)
{
check(0, "subscript out of range");
return (*data)[i];
}
// P592 E16.12.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "Blob Template.h"
#include "BlobPtr.h"
#include <iostream>
using namespace std;
int main()
{
Blob<int> iBlob{ 1,2,3,4,5 };
Blob<int> iBlob2 = iBlob;
Blob<int> iBlob3{ 1,2,3,4,5 };
cout << "iBlob == iBlob2: " <<(iBlob == iBlob2) << endl;
cout << "iBlob == iBlob3: " << (iBlob == iBlob3) << endl;
cout <<"iBlob.back(): " << iBlob.back() << endl;
cout << "iBlob.empty(): " << iBlob.empty() << endl;
cout << "iBlob[0]: " << iBlob[0] << endl;
cout << "iBlob.begin(): " << *iBlob.begin() << endl;
cout << "iBlob.end(): " << *(--iBlob.end()) << endl;
cout << "iBlob.size(): " << iBlob.size() << endl;
iBlob.pop_back();
cout << "iBlob.size(): " << iBlob.size() << endl;
iBlob.push_back(5);
cout << "iBlob.size(): " << iBlob.size() << endl;
Blob<string> sBlob{ "eleven","past", "five" };
cout << "sBlob.size(): " << sBlob.size() << endl;
return 0;
}
P595 E16.19
//print.h
#pragma once
template<typename T>
void print(const T& t)
{
//一开始写成了t::size_type i = 0
//C++默认用作用域运算符访问的是静态成员
//如果想访问类型成员需要使用关键字typename
typename T::size_type i = 0;
while (i != t.size())
cout << t[i++] << " ";
/*
//可以用标准库函数begin()和end(),也可以用容器自带的begin()和end()成员
//使用迭代器的方法比上一题使用范围更广:可以用于list和forward_list等类型
//list和forward_list的元素不是顺序存储的,因此上一题的解法:指针++,--是没有意义的
auto b = begin(t);
auto e = end(t);
while (b != e)
cout << *b++ << " ";
*/
}
// P595 E16.19.cpp: 定义控制台应用程序的入口点。
#include "stdafx.h"
#include "print.h"
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> iv{ 1,2,3,4,5 };
print(iv);
return 0;
}
P600 E16.28
//my_shared_ptr.h
#pragma once
template <typename T>
class my_shared_ptr
{
friend void swap(my_shared_ptr<T>&, my_shared_ptr<T>&);//member function or not
public:
my_shared_ptr<T> (const T* t = nullptr);//默认构造函数
my_shared_ptr<T> (const my_shared_ptr<T>&);
my_shared_ptr<T>& operator= (const my_shared_ptr<T>&);
~my_shared_ptr<T>();
T& operator*() const;
T* operator->() const;//这个操作符返回指针,然后呢
T* get() const;
void swap(my_shared_ptr<T>&);
my_shared_ptr<T> my_make_shared<T>(const T&);//member function or not
bool unique();
size_t use_count();
void reset();
void reset(T* p);
//P413 p.reset(q,d)这个d里面是否也是用delete删除指针的,d写成全局函数吗
//P412 shared_ptr<T> p(q,d)
//P412 shared_ptr<T> p(u) 写完my_unique_ptr再写,友元
private:
T* m_p = nullptr;//initialize it or not
static size_t use_count = 0;
};
template <typename T>
my_shared_ptr<T>::my_shared_ptr<T>(const T* p = nullptr)
{
if (p)
{
m_p = p;
++use_count;
}
}
template <typename T>
my_shared_ptr<T>::my_shared_ptr<T>(const my_shared_ptr<T>& rhs)
{
m_p = rhs.m_p;
++use_count;
--rhs.use_count;
}
template <typename T>
my_shared_ptr<T>& my_shared_ptr<T>::operator= (const my_shared_ptr<T>& rhs)
{
if (m_p == rhs.m_p)
return *m_p;
m_p = rhs.m_p;
++use_count;
--rhs.use_count;
}
template <typename T>
my_shared_ptr<T>::~my_shared_ptr<T>()
{
if (use_count == 0)
{
delete m_p;
m_p = nullptr;
}
}
template <typename T>
T& my_shared_ptr<T>::operator*() const
{
return *m_p;
}
template <typename T>
T* my_shared_ptr<T>:: operator->() const
{
return &this->operator*();
}
template <typename T>
T* my_shared_ptr<T>::get() const
{
return m_p;
}
template <typename T>
void my_shared_ptr<T>::swap(my_shared_ptr<T>& p)
{
my_shared_ptr<T> temp = m_p;
m_p = p;
p = temp;
}
template <typename T>
void swap(my_shared_ptr<T>& p, my_shared_ptr<T>& q)//member function or not
{
my_shared_ptr<T> temp = p;
p = q;
q = temp;
}
template <typename T>
my_shared_ptr<T> my_shared_ptr<T>::my_make_shared<T>(const T& t)
{
return my_shared_ptr(new T(t));
}
template <typename T>
bool my_shared_ptr<T>::unique()
{
return use_count == 1;
}
template <typename T>
size_t my_shared_ptr<T>::use_count()
{
return use_count;
}
template <typename T>
void my_shared_ptr<T>::reset()
{
if (use_count == 1)
{
~my_shared_ptr<T> ();
}
}
template <typename T>
void my_shared_ptr<T>::reset(T* p)
{
m_p = p;
p = nullptr;//?
}
//my_unique_ptr.h
#pragma once
#include "DebugDelete.h"
template <typename T>
class my_unique_ptr
{
public:
my_unique_ptr<T>(const T* p = nullptr);
~my_unique_ptr();
my_unique_ptr<T>(const my_unique_ptr<T>&) = delete;
my_unique_ptr<T>& operator= (const my_unique_ptr<T>&) = delete;
my_unique_ptr<T>* release();
//使用默认参数new_p就可以在一个函数里包括提供内置指针参数和不提供的两种情况
void reset(T* new_p = nullptr);
private:
T* m_p;
static size_t use_count = 0;//
};
template <typename T>
my_unique_ptr<T>::my_unique_ptr<T>(const T* p = nullptr)
{
if (p)
m_p = p;
}
template <typename T>
my_unique_ptr<T>::~my_unique_ptr()
{
if(m_p)//删除指针前应该检查指针是否为空
delete m_p;
}
template <typename T>
my_unique_ptr<T>* my_unique_ptr<T>::release()
{
T* temp = m_p;
m_p = nullptr;
return temp;
}
template <typename T>
void my_unique_ptr<T>::reset(T* new_p = nullptr)//P418表格说reset的参数是内置指针
{
if (new_p)
{
delete m_p;
}
m_p = new_p;
}