C++11の新しい容器(array,無秩序容器,tupleメタグループ)

30869 ワード

文書ディレクトリ
  • shrink_to_fit
  • array
  • forward_list
  • 無秩序容器
  • ユニットtuple
  • tuple
  • の定義と初期化
  • tupleメンバー
  • へのアクセス
  • tupleのメンバー数とメンバータイプ
  • 合併tuple
  • tuple
  • を巡る
  • C++11実現tupleの遍歴
  • C++14/17
  • を巡る
  • 参考資料
  • shrink_to_fit
    // VS2019
    int main() {
    	vector<int> arr(100);
    	arr.emplace_back(10);
    	cout << arr.size() << endl;  //   101
    	cout << arr.capacity() << endl; //   150
    	arr.shrink_to_fit();
    	cout << arr.size() << endl;  //   101 
    	cout << arr.capacity() << endl; //   101
    	arr.swap(vector<int>());
    	cout << arr.size() << endl;  //   0
    	cout << arr.capacity() << endl; //   0
    }
    

      上から分かるように、VS下ではvector拡張が1.5倍(Linux下では2倍).拡張後、49*sizeof(int)の不要メモリが多くなったため、C++11はshrink_を提供したto_fit関数はこの部分のメモリを解放しますが、この関数は要求にすぎず、必ずしも成功するとは保証されません.
      C++11以前はclear()関数がパージ容器内の要素の個数であることが知られていたが、メモリは解放されていなかったので、一般的にはswap関数で解放されていたが、clear後にshrink_to_fit関数を使用してメモリを解放します.
    array
    この容器を導入した目的はC中の配列を置き換えることであり,C中の配列は安全検査をしていないため,C++はこの定長容器を提供した.C++STLとの互換性のためにも、従来のCと互換性のある汎用関数begin()とend()関数が提供されているが、arrayはより規範的である.
    int main() {
    	constexpr int size = 10;
    	array<int, size> arr{ 1, 2, 5, 3, 5, 1 };
    	sort(arr.begin(), arr.end());
    }
    

    forward_list
      listは双方向チェーンテーブルでforward_Listは一方向チェーンテーブルであり,効率が高いため,容器にsize()メソッドを提供していない容器である.
    むじゅんようき
     mapとsetの下層はいずれも赤黒樹によって実現され,その検索/増加/削除の時間的複雑さはO(log(n))であり,この2つの容器は秩序化されており,すなわち要素がサポートされる
      C++11はunordered_を提供しますmap/setは,その下層がハッシュテーブルによって実現されるので,時間的複雑度はいずれもO(1)であり,無秩序である.
    メタグループtuple
    ジルコニウムtupleはpairのテンプレートに似ている.各pairのメンバータイプは異なりますが、pairには2人のメンバーしかいません.1つのtupleには任意の数のメンバーがいます.各決定されたtupleタイプのメンバー数は固定されているが、1つのtupleタイプのメンバー数は別のtupleタイプと異なることができる.次はtupleがサポートする操作です.
    tupleの定義と初期化
      私たちがtupleに登ったとき、各メンバーのタイプを指摘する必要があります.
    tuple<int, double, size_t> threeD;  //           0
    tuple<string, vector<double>, list<int>> someVal("constants", { 3.15,22 }, { 0,1 });
    

    tupleオブジェクトを作成する場合は、tupleのデフォルトのコンストラクション関数を使用して、各メンバーの値を初期化できます.someValのように、各メンバーに初期値を明示的に指定することもできます.tupleという構造関数はexplicitなので,直接初期化しなければならない.
    類似make_pair関数、標準ライブラリにもmake_が用意されていますtupleオブジェクトを生成するtuple関数:
    auto item = make_tuple("hello", 3, 3.0); // item   tuple  
    

    tupleメンバーへのアクセス
      pairには2つのメンバーしかいないのでfirstとsecondでアクセスできますが、tupleのメンバーは固定されていないので、メンバーを設定してアクセスすることはできません.tupleのメンバーにアクセスするには、標準ライブラリ関数テンプレートgetを使用します.getを使用するには、いくつかのメンバーにアクセスしたいことを示す明示的なテンプレートの実パラメータを指定する必要があります.getにtupleオブジェクトを渡し、指定したメンバーの参照を返します.
    auto item = make_tuple("hello", 3, 3.0); // item   tuple  
    auto book = get<0>(item);  //   item      
    

      はtieによって解包することもできる:
    int main() {
    	auto item = make_tuple("hello", 3, 3.0); // item   tuple  
    	using type = decltype(item);
    	tuple_element<0, type>::type x;   //         
    	tuple_element<1, type>::type y;
    	tuple_element<2, type>::type z;
    	tie(x, y, z) = item;
    	cout << x << " " << y << " " << z << endl;  //   hello,3, 3
    }
    

    パケットを解く場合、ある位置の値だけを解く場合はstd::ignoreプレースホルダで、ある位置を理解できない値を表すことができます.
    tie(x, ignore, ignore) = item;   //        ,      y z
    

      C++14は、タイプによってtupleメンバーを取得できます.
    int main() {
    	auto item = make_tuple("hello", 3, 3.0); // item   tuple  
    	using type = decltype(item);
    	cout << get<int>(item) << endl; //   3
    	cout << get<double>(item) << endl; //   3
    	cout << get<const char*>(item) << endl; //   hello
    }
    

    tuple内のメンバーの数とメンバータイプ
    クラステンプレートtuple_size::valueは、与えられたtupleタイプのメンバーの数を取得し、decltypeによってtupleTypeを取得することができる.
      はクラステンプレートtuple_を介してもよいElement::tupleタイプで指定したメンバーのタイプを取得するtype:
    int main() {
    	auto item = make_tuple("hello", 3, 3.0); // item   tuple  
    	auto book = get<0>(item);  //   item      
    	using type = decltype(item);
    	size_t sz = tuple_size<type>::value;
    	cout << sz << endl;   //   3
        tuple_element<1, type>::type cnt = get<1>(item);  // cnt    int
    }
    

    マージtuple
    ゞ  可以通过tuple_ゞcatは2つのtupleを結合する.
    tupleを巡る
    template<typename... Args>
    std::ostream& operator<<(std::ostream& os, const std::tuple<Args...>& t)
    {
        os << "(" << std::get<0>(t);
        for (size_t i = 1; i < sizeof...(Args) << ++i)
            os << ", " << std::get<i>(t);
        return os << "]";
    }
    
    int main(int, char**)
    {
        cout << make_tuple("InsideZhang", 23, "HeNan") << endl;
                //     ,    i           
        return 0;
    }
    
    //                                   :
    template<typename Tuple>
    void tuple_print(const Tuple& t, size_t N, std::ostream& os)
    {
        if (N != 1)
            tuple_print(t, N-1, os);
        os << std::get<N-1>(t);
    }
    

     以上のコード、すなわちパラメータ伝達方式による非タイプテンプレートパラメータの付与は、コンパイルが通過しない.getパラメータは、コンパイル時に定数式である必要があります.
    C++11 tupleの遍歴を実現
    template<typename Tuple, size_t N>
    struct tuple_print {
        static void print(const Tuple& t, ostream& os) {
            tuple_print<Tuple, N - 1>::print(t, os);
            os << ", " << get<N - 1>(t);
        }
    };
    //         
    template<typename Tuple>
    struct tuple_print<Tuple, 1> {
        static void print(const Tuple& t, ostream& os) {
            os << "(" << get<0>(t);
        }
    };
    
    // operator<<
    template<typename... Args>
    ostream& operator << (ostream & os, const tuple<Args...> & t) {
        tuple_print<decltype(t), sizeof...(Args)>::print(t, os);
        return os << ")";
    }
    
    
    int main() {
        auto t1 = std::make_tuple("InsideZhang", 23, "HeNan");
        auto t2 = std::make_tuple("InsideLi", 23, "AnHui");
        cout << std::tuple_cat(t1, t2) << endl;
        //  (InsideZhang, 23, HeNan, InsideLi, 23, AnHui)
    }
    

    C++14/17遍歴
    ここは空いてから補充します.
      
    参考資料
    (1)『C++Primer』(2)『クイックハンドC++11/14』(3)https://blog.csdn.net/yockie/article/details/89511498