C++Helper--在原std::vector基礎上改進接口

  在STL容器中,vector可能是最受歡迎的了,因爲他們只需要往向容器中添加元素,而不用事先操心容器大小的問題。

  不過用過的都知道,vector接口不夠豐富。於是這裏,將在原vector的基礎上,拓展新的接口,方便實際場景中的運用。

  本文源碼見【完整代碼】章節,或GitHub:https://github.com/deargo/cpphelper

vector介紹

  vector是表示可以改變大小的數組的序列容器。

  就像數組一樣,vector爲它們的元素使用連續的存儲位置,這意味着它們的元素也可以使用到其元素的常規指針上的偏移來訪問,而且和數組一樣高效。但是與數組不同的是,它們的大小可以動態地改變,它們的存儲由容器自動處理。

  在內部,vector使用一個動態分配的數組來存儲它們的元素。這個數組可能需要重新分配,以便在插入新元素時增加大小,這意味着分配一個新數組並將所有元素移動到其中。就處理時間而言,這是一個相對昂貴的任務,因此每次將元素添加到容器時矢量都不會重新分配。

  相反,vector容器可以分配一些額外的存儲以適應可能的增長,並且因此容器可以具有比嚴格需要包含其元素(即,其大小)的存儲更大的實際容量。庫可以實現不同的策略的增長到內存使用和重新分配之間的平衡,但在任何情況下,再分配應僅在對數生長的間隔發生尺寸,使得在所述載體的末端各個元件的插入可以與提供分期常量時間複雜性。

  因此,與數組相比,載體消耗更多的內存來交換管理存儲和以有效方式動態增長的能力。

  與其他動態序列容器(deques,lists和 forward_lists )相比,vector非常有效地訪問其元素(就像數組一樣),並相對有效地從元素末尾添加或移除元素。對於涉及插入或移除除了結尾之外的位置的元素的操作,它們執行比其他位置更差的操作,並且具有比列表和 forward_lists 更不一致的迭代器和引用。

vector接口改進

新增元素

  現在常用的接口insert、push_back、emplace及emplace_back。

  在實際中,我們需要合併兩個vector,循環新增,太耗時好性能;insert接口太長;而算法中的merge,還有注意源容器的空間足夠和有序。

  能不能簡單點,比如直接相加,或者append。如果要一次性插入多個元素,不需要多次調用接口,而像流運算符那樣插入呢。

  改進的代碼中,也新增了前部插入的接口。但在這裏不推薦使用,因爲每次插入,已有的元素都必須騰出空間,往後位移,效率是及其低下,如果大量的前部插入,則建議使用list。

刪除元素

  刪除元素,絕對是vector容器最大的一個坑,誰用誰知道。

  clear清空了元素,但沒有釋放空間,容量依然不變,雖然c++11新提供了新的接口shrink_to_fit ,但難免忘記,也感覺多餘。

  swap,可以清空元素,又可以回收空間,但還要構造一個空的對象,麻煩。

  pop_back從尾部刪除元素,同樣沒有釋放空間;

  erase只修改了迭代器,容量亦不變,並返回刪除元素的下一個元素位置,在循環操作時極易出錯。

  算法中的remove和remove_if也沒有真正刪除元素,甚至連 size 都不變,還使用繁瑣。

  所以這裏急需要一個,能夠完整刪除元素的接口,而且可以刪除任意位置的元素。

遍歷查找

  我們一般使用迭代器、at、[ ],和算法中的 find 函數進行遍歷。

  at巨慢,find繁瑣也慢,下標索引遍歷 [ ]  比迭代器較快,但也要寫個循環遍歷,業務代碼做了不必要的操作。

  於是本文新增了檢索接口,屏蔽了遍歷環節。另外也新增了存在、索引獲取的接口。

數據轉換

  在STL容器中,vector、list 和 set 各有優劣,實際使用中,經常需要進行這幾種類型之間的轉換,於是也新增了vector與其他兩者的互相轉換和賦值。

集成算法

  在STL中,也提供了大量的算法函數,以應對vector、map、set、list、queue等的操作,不過單獨使用,參數複雜,用起來不方便,於是這裏嘗試將find、count、sort、equal、fill、copy等算法加以集成,使其和原始的算法函數沒有任何區別。

完整代碼

#pragma once

#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif

#include <vector>
#include <set>
#include <list>
#include <algorithm>
#include <functional>

namespace CppHelper
{
template<class Type , class Alloc = std::allocator<Type> >
class CVector : public std::vector<Type,Alloc>{
    using StdVec = std::vector<Type,Alloc>;

public:
    explicit CVector(const Alloc& alloc = Alloc()):StdVec(alloc) {}                                          //默認構造函數
    explicit CVector(size_t n, const Type& val = Type(), const Alloc& alloc = Alloc()):StdVec(n,val,alloc){} //容量構造函數
    CVector(CVector&& other):StdVec(std::forward<CVector>(other)){ }                                                           //拷貝構造函數
    CVector(const std::vector<Type,Alloc>& vec){ StdVec::assign(vec.begin(), vec.end()); }                   //可用std::vector初始化
    template <class InitIterator>                                                                            //可用迭代器初始化
    CVector (InitIterator first, InitIterator last, const Alloc& alloc = Alloc()):StdVec(first,last,alloc){}
    explicit CVector(const std::set<Type>& set){ StdVec::assign(set.begin(), set.end()); }                   //可用std::set初始化
    explicit CVector(const std::list<Type>& list){ StdVec::assign(list.begin(), list.end()); }               //可用std::list初始化

public:
    operator std::vector<Type,Alloc>(){ return *this; }                                                  //類型轉換函數,可直接轉換爲std::vector
    bool operator == (const CVector& other) const{ return StdVec::size()==other.size() && std::equal(StdVec::begin(),StdVec::end(),other.begin()); }
    bool operator !=(const CVector& other) const { return StdVec::size()!=other.size() || false == std::equal(StdVec::begin(),StdVec::end(),other.begin()); }
    CVector& operator =(const CVector& other){StdVec::assign(other.begin(), other.end()); return *this;} //賦值構造函數
    CVector& operator +(const CVector& other){ push_back(other); return *this; }
    CVector& operator +=(Type&& value){ push_back(std::forward<Type>(value)); return *this; }
    CVector& operator +=(const CVector& other){ push_back(other); return *this; }
    CVector& operator<<(Type&& value){ push_back(std::forward<Type>(value)); return *this; }
    CVector& operator<<(const CVector& other){ push_back(other); return *this; }
    CVector& operator<<(const std::set<Type>& set){ push_back(set); return *this; }
    CVector& operator<<(const std::list<Type>& list){ push_back(list); return *this; }

public:
    void append(Type&& value){ push_back(std::forward<Type>(value)); }
    void append(const CVector& other){ push_back(other); }
    void append(const std::set<Type>& set){ push_back(set); }
    void append(const std::list<Type>& list){ push_back(list); }

    bool contains(Type&& value) const
    {
        return  std::find(StdVec::begin(), StdVec::end(),std::forward<Type>(value)) != StdVec::end();
    }
    template <class CompareFunction>  //需要傳入類似 bool (*compareFunction)(Type&& v1, Type&& v2) 的二元謂詞函數,v1爲element-value,v2爲input-value
    bool contains(Type&& value,CompareFunction compareFunction) const
    {
        return  std::find_if(StdVec::begin(), StdVec::end(),
                             std::bind(compareFunction,std::placeholders::_1,std::forward<Type>(value)))
                != StdVec::end();
    }

    template <class CopyIterator>
    typename CVector::iterator copy(typename CVector::iterator thisDesc, CopyIterator first,CopyIterator last)
    {
        return std::copy(first,last,thisDesc);
    }
    template <class CopyIterator, class Function>
    typename CVector::iterator copy(typename CVector::iterator thisDesc, CopyIterator first,CopyIterator last, Function func)
    {
        return std::copy_if(first,last,thisDesc, func);
    }
    template <class CopyIterator>
    typename CVector::iterator copy(typename CVector::iterator thisDesc, CopyIterator first,typename CVector::size_type n)
    {
        return std::copy_n(first,n,thisDesc);
    }

    int count(Type&& value) const
    {
        return std::count(StdVec::begin(), StdVec::end(),std::forward<Type>(value));
    }
    template <class CompareFunction>  //需要傳入類似 bool (*compareFunction)(Type&& v1, Type&& v2) 的二元謂詞函數,v1爲element-value,v2爲input-value
    int count(Type&& value,CompareFunction compareFunction) const
    {
        return  std::count_if(StdVec::begin(), StdVec::end(),
                              std::bind(compareFunction,std::placeholders::_1,std::forward<Type>(value)));
    }

    bool equal(const CVector& other) const { return this->operator==(other); }
    template <class CompareIterator>
    bool equal(CompareIterator compareIterator) const
    {
        return std::equal(StdVec::begin(),StdVec::end(),compareIterator);
    }
    template <class CompareIterator, class CompareFunction> //需要傳入類似 bool (*compareFunction)(Type&& v1, Type&& v2) 的二元謂詞函數,v1爲element-value,v2爲input-value
    bool equal(CompareIterator compareIterator,CompareFunction compareFunction) const
    {
        return std::equal(StdVec::begin(),StdVec::end(),compareIterator,compareFunction);
    }

    void fill(Type&& value,typename CVector::iterator first = StdVec::begin(), typename CVector::iterator last = StdVec::end()) { std::fill(first,last,std::forward<Type>(value)); }
    void fill(typename CVector::size_type n, Type&& value, typename CVector::iterator first = StdVec::begin())  { std::fill_n(first,n,std::forward<Type>(value)); }

    typename CVector::iterator find(Type&& value)
    {
        return  std::find(StdVec::begin(), StdVec::end(),std::forward<Type>(value));
    }
    typename CVector::const_iterator find(Type&& value) const
    {
        return  std::find(StdVec::begin(), StdVec::end(),std::forward<Type>(value));
    }
    template <class CompareFunction>  //需要傳入類似 bool (*compareFunction)(Type&& v1, Type&& v2) 的二元謂詞函數,v1爲element-value,v2爲input-value
    typename CVector::iterator find(Type&& value,CompareFunction compareFunction)
    {
        return  std::find_if(StdVec::begin(), StdVec::end(),
                             std::bind(compareFunction,std::placeholders::_1,std::forward<Type>(value)));
    }
    template <class CompareFunction>  //需要傳入類似 bool (*compareFunction)(Type&& v1, Type&& v2) 的二元謂詞函數,v1爲element-value,v2爲input-value
    typename CVector::const_iterator find(Type&& value,CompareFunction compareFunction ) const
    {
        return  std::find_if(StdVec::begin(), StdVec::end(),
                             std::bind(compareFunction,std::placeholders::_1,std::forward<Type>(value)));
    }

    const Type& first() const{ return StdVec::operator[](0); }

    template <class Function>
    Function for_each(Function func){ return std::for_each(StdVec::begin(), StdVec::end(),func); }

    int index(Type&& value) const {
        for (int idx = 0; idx <(int)StdVec::size();++idx){
            if (StdVec::operator[](idx)==std::forward<Type>(value)) return idx;
        }
        return -1;
    }
    template <class CompareFunction>  //需要傳入類似 bool (*compareFunction)(Type&& v1, Type&& v2) 的二元謂詞函數,v1爲element-value,v2爲input-value
    int index(Type&& value,CompareFunction compareFunction) const {
        for (int idx = 0; idx <(int)StdVec::size();++idx){
            if (compareFunction(StdVec::operator[](idx),std::forward<Type>(value))) return idx;
        }
        return -1;
    }

    void insert(unsigned int index, Type&& value){ StdVec::emplace(StdVec::begin() + index, std::forward<Type>(value)); }

    const Type& last() const{ return StdVec::operator[](StdVec::size() - 1); }

    void pop_front(){ if (!StdVec::empty()) StdVec::erase(StdVec::begin()); }

    void prepend(Type&& value) { StdVec::emplace(StdVec::begin(), std::forward<Type>(value)); }

    void push_back(Type&& value){ StdVec::emplace_back(std::forward<Type>(value)); }
    void push_back(const CVector& other){  StdVec::insert(StdVec::end(),other.begin(),other.end());}
    void push_back(const std::set<Type>& set){ StdVec::insert(StdVec::end(),set.begin(),set.end()); }
    void push_back(const std::list<Type>& list){ StdVec::insert(StdVec::end(),list.begin(),list.end()); }

    void push_front(Type&& value) { StdVec::emplace(StdVec::begin(), std::forward<Type>(value)); }

    void remove(Type&& value)
    {
        StdVec::erase(std::remove(std::begin(*this), std::end(*this),std::forward<Type>(value)), std::end(*this));
    }
    template <class CompareFunction>  //需要傳入類似 bool (*compareFunction)(Type&& v1, Type&& v2) 的二元謂詞函數,v1爲element-value,v2爲input-value
    void remove(Type&& value, CompareFunction compareFunction)
    {
        StdVec::erase(std::remove_if(std::begin(*this), std::end(*this),
                                     std::bind(compareFunction,std::placeholders::_1,std::forward<Type>(value))),
                      std::end(*this));
    }
    void removeAll(){ StdVec::clear(); StdVec::shrink_to_fit();}
    void removeAt(unsigned int index){ StdVec::erase(StdVec::begin() + index); }
    void removeFirst(){ this->pop_front(); }
    void removeLast(){ StdVec::pop_back(); }
    void removeRange(unsigned int from, unsigned int to)
    {
        while(to-from)
        {
            StdVec::erase(StdVec::begin()+from);
            to--;
        }
    }

    void replace(unsigned int index, Type&& value){ StdVec::operator[](index) = std::forward<Type>(value); }

    void sort(){return std::sort(StdVec::begin(),StdVec::end());}
    template <class CompareFunction>  //需要傳入類似 bool (*compareFunction)(Type&& v1, Type&& v2) 的二元謂詞函數,v1爲element-value,v2爲input-value
    void sort(CompareFunction compareFunction){return std::sort(StdVec::begin(),StdVec::end(),compareFunction);}

    void swap (std::vector<Type,Alloc>& other){ return StdVec::swap(other);}
    void swap (unsigned int index1,unsigned int index2){ return std::swap(StdVec::operator[](index1),StdVec::operator[](index2));}

    const Type& takeAt(unsigned int index) const{ return StdVec::operator[](index); }
    const Type& takeFirst() const { return StdVec::operator[](0); }
    const Type& takeLast() const { return StdVec::operator[](StdVec::size() - 1); }

    std::vector<Type> toStdVec() const { return *this; }
    std::list<Type> toStdList() const{ return std::list<Type>(StdVec::begin(),StdVec::end());}
    std::set<Type> toStdSet() const{ return std::set<Type>(StdVec::begin(),StdVec::end());}

    const Type& value(unsigned int index) const { return StdVec::operator[](index); }
};

}

測試代碼

    typedef std::set<int> StdSet;
    typedef std::list<int> StdList;
    typedef std::vector<int> StdVec;
    typedef CppHelper::CVector<int> NewVec;


#define TEST_vec_bool(b) (b ? "true" : "false")
#define TEST_vec_exec(flage,code) cout << flage << code << endl
#define TEST_vec_print(flage,val) cout << flage ;\
    for(auto it = val.begin();it!=val.end();++it) cout << *it << " ";\
    if(val.empty()) cout << "empty";\
    cout << endl

    int arr[] = {1,2,3,4,5,6,7,8,9};
    StdSet stdSet{11,12,13,14,15,16,17,18,19};
    StdList stdList{21,22,23,24,25,26,27,28,29};
    StdVec stdVec1{31,32,33,34,35,36,37,38,39};
    StdVec stdVec2{41,42,43,44,45,46,47,48,49};
    NewVec newVec1;
    NewVec newVec2(10);
    NewVec newVec3(stdSet);
    NewVec newVec4(stdList);
    NewVec newVec5(stdVec1);
    NewVec newVec6(arr,arr+9);

    TEST_vec_print(" stdSet: ",stdSet);
    TEST_vec_print("stdList: ",stdList);
    TEST_vec_print("stdVec1: ",stdVec1);
    TEST_vec_print("newVec1: ",newVec1);
    TEST_vec_print("newVec2: ",newVec2);
    TEST_vec_print("newVec3: ",newVec3);
    TEST_vec_print("newVec4: ",newVec4);
    TEST_vec_print("newVec5: ",newVec5);
    TEST_vec_print("newVec6: ",newVec6);

    TEST_vec_exec ("newVec3 == newVec3 ? : ",TEST_vec_bool(newVec3 == newVec4));
    TEST_vec_exec ("newVec3 != newVec3 ? : ",TEST_vec_bool(newVec3 != newVec4));

    newVec1 = newVec3;
    newVec1 += newVec4;
    newVec1 << 100 << 200<< 300;
    TEST_vec_print("newVec1: ",newVec1);

    TEST_vec_exec ("newVec1.size()    : ",newVec1.size());
    TEST_vec_exec ("newVec1.capacity(): ",newVec1.capacity());
    newVec1.clear();
    TEST_vec_exec ("newVec1.size()    : ",newVec1.size());
    TEST_vec_exec ("newVec1.capacity(): ",newVec1.capacity());
    TEST_vec_print("newVec1: ",newVec1);

    newVec1.append(555);
    newVec1.append(newVec3);
    newVec1.append(stdSet);
    newVec1.append(stdList);
    TEST_vec_print("newVec1: ",newVec1);

    newVec1.clear();
    newVec1.resize(20);
    TEST_vec_print("newVec3      : ",newVec3);
    TEST_vec_print("newVec1      : ",newVec1);
    newVec1.copy(newVec1.begin(),newVec3.begin()+3,newVec3.end());
    TEST_vec_print("newVec1.copy1: ",newVec1);
    newVec1.copy(newVec1.begin(),newVec3.begin(),newVec3.end(),[](int v){ return v>15; });
    TEST_vec_print("newVec1.copy2: ",newVec1);
    newVec1.copy(newVec1.begin()+6,newVec3.begin(),3);
    TEST_vec_print("newVec1.copy3: ",newVec1);

    newVec1.contains(200,[](const int& v1,int v2){ return v1>v2;});
    TEST_vec_exec ("newVec1.contains(555) : ",TEST_vec_bool(newVec1.contains(555)));
    TEST_vec_exec ("newVec1.contains(>200): ",TEST_vec_bool(newVec1.contains(200,[](const int& v1,int v2){ return v1>v2;})));
    TEST_vec_exec ("newVec1.count(11) : ",newVec1.count(11));
    TEST_vec_exec ("newVec1.count(>28): ",newVec1.count(28,[](int v1, int v2){ return v1>v2;}));

    TEST_vec_print("newVec2       : ",newVec2);
    newVec2.fill(4,111,newVec2.begin());
    TEST_vec_print("newVec2.fill-1: ",newVec2);
    newVec2.fill(222,newVec2.begin()+6,newVec2.end());
    TEST_vec_print("newVec2.fill-2: ",newVec2);

    TEST_vec_print("newVec3                     : ",newVec3);
    TEST_vec_print("stdSet                      : ",stdSet);
    TEST_vec_exec ("newVec3.equal(stdSet.begin) : ",TEST_vec_bool(newVec3.equal(stdSet.begin())));
    newVec2 = newVec3;
    TEST_vec_print("newVec2                : ",newVec2);
    TEST_vec_exec ("newVec2.equal(newVec3) : ",TEST_vec_bool(newVec2.equal(newVec3)));

    TEST_vec_exec("newVec2.find(13)  : ",*(newVec1.find(13)));
    TEST_vec_exec("newVec2.find(<=13): ",*(newVec1.find(13,[](int vecVal,int findVal){ return vecVal<=findVal;})));

    cout << "newVec1.for_each: ";
    newVec1.for_each([](int v){ cout << v << " "; });
    cout << endl;

    TEST_vec_exec("newVec1.index(15)            : ",newVec1.index(15));
    TEST_vec_exec("newVec1.index(<100 && >=15)  : ",newVec1.index(15,[](int vecVal,int findVal){ return vecVal<100&& vecVal>=findVal;}));

    TEST_vec_print("newVec1        : ",newVec1);
    newVec1.insert(newVec1.size(),666);
    TEST_vec_exec("newVec1.last() : ",newVec1.last());

    newVec1.prepend(333);
    TEST_vec_exec("newVec1.first(): ",newVec1.first());
    TEST_vec_print("newVec1        : ",newVec1);

    newVec1.clear();
    TEST_vec_print("newVec1  : ",newVec1);
    TEST_vec_print("newVec4  : ",newVec3);
    TEST_vec_print(" stdSet: ",stdSet);
    TEST_vec_print("stdList: ",stdList);
    newVec1.push_back(11);
    newVec1.push_back(newVec3);
    newVec1.push_back(stdSet);
    newVec1.push_back(stdList);
    newVec1.push_front(444);
    TEST_vec_print("newVec1  : ",newVec1);

    newVec1.remove(11);
    TEST_vec_print("newVec1 remove-1 : ",newVec1);
    newVec1.remove(15,[](int vecVal,int findVal){ return vecVal < findVal+2 && vecVal >= findVal-2;});
    TEST_vec_print("newVec1 remove-2 : ",newVec1);
    newVec1.removeRange(3,6);
    TEST_vec_print("newVec1 remove-3 : ",newVec1);
    newVec1.removeFirst();
    newVec1.removeLast();
    newVec1.removeAt(3);
    TEST_vec_print("newVec1 remove2-4 : ",newVec1);
    TEST_vec_exec("newVec1.size()     : ",newVec1.size());
    TEST_vec_exec("newVec1.capacity() : ",newVec1.capacity());
    newVec1.removeAll();
    TEST_vec_print("newVec1 removeAll  : ",newVec1);
    TEST_vec_exec("newVec1.size()     : ",newVec1.size());
    TEST_vec_exec("newVec1.capacity() : ",newVec1.capacity());

    newVec1 = newVec3;
    TEST_vec_print("newVec1=newVec3          : ",newVec1);
    newVec1.replace(3,333);
    TEST_vec_print("newVec1.replace(3,333)   : ",newVec1);
    newVec1.sort();
    TEST_vec_print("newVec1.sort()    : ",newVec1);
    newVec1.sort([](int a,int b){return a>b;});
    TEST_vec_print("newVec1.sort(a>b) : ",newVec1);

    TEST_vec_print("newVec3               : ",newVec3);
    newVec1.swap(newVec3);
    TEST_vec_print("newVec1.swap(newVec3) : ",newVec1);
    TEST_vec_print("newVec3               : ",newVec3);
    newVec1.swap(3,7);
    TEST_vec_print("newVec1.swap(3,7) : ",newVec1);

    TEST_vec_exec("newVec1.takeAt(3)   : ",newVec1.takeAt(3));
    TEST_vec_exec("newVec1.takeFirst() : ",newVec1.takeFirst());
    TEST_vec_exec("newVec1.takeLast()  : ",newVec1.takeLast());
    TEST_vec_exec("newVec1.value(7)    : ",newVec1.value(7));


    TEST_vec_print("newVec5       : ",newVec5);
    TEST_vec_print("stdSet        : ",stdSet);
    TEST_vec_print("stdList       : ",stdList);
    stdSet = newVec5.toStdSet();
    stdList = newVec5.toStdList();
    TEST_vec_print("stdSet        : ",stdSet);
    TEST_vec_print("stdList       : ",stdList);

更多資料

  本文完整源碼:https://github.com/deargo/cpphelper

  更多學習資料:https://blog.csdn.net/aguoxin

發佈了16 篇原創文章 · 獲贊 11 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章