本週課程老師講解了各類容器的部分使用方法,而且對它們處理元素的速度作了測試,使學生對於各類容器的特色有了一些認識。還講了STL的體系結構和分配器的使用。這些內容涉及的基礎知識C++ Primer上面都有,仍是那句話,我再抄一遍沒意義,因此我把C++ Primer模板那一章的習題作了一些,這章的題除了涉及到模板,還整合了不少以前學習容器的時候的習題(每每是用模板實現類或者函數,其中有不少使用容器的練習)。能力有限,這一章的題我沒有都寫完,由於其中有些題目仍是挺複雜的。我把目前寫完的先記在這篇筆記裏,沒寫完的和有疑問的我研究之後再寫進來。ios
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.19this
//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.28spa
//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; }