Boolan STL与泛型编程第一周笔记

Posted dana-coder

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Boolan STL与泛型编程第一周笔记相关的知识,希望对你有一定的参考价值。

本周课程老师讲解了各种容器的部分使用方法,并且对它们处理元素的速度做了测试,使学生对于各种容器的特点有了一些认识。还讲了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;
}

 

以上是关于Boolan STL与泛型编程第一周笔记的主要内容,如果未能解决你的问题,请参考以下文章

[GeekBand] STL与泛型编程

模板与泛型编程

c++标准容器库与泛型编程

c++标准容器库与泛型编程

c++标准容器库与泛型编程

201621044079 韩烨作业09-集合与泛型