イテレータ(第4章)(項目26、27、28、29)

 

特記事項:C ++ 11標準は、著者がこの本を書いた時点ではリリースされていません。コンパイラの製造元によってC ++標準の実装にいくつかの違いがあり、現在および最新の本の内容の一部につながっています。 C ++標準とほとんどのコンパイラの動作。違いに特に注意してください。

項目26:イテレータはconst_iterator、reverse_iterator、const_reverse_iteratorよりも優先されます

本に記載されている例では、連続ストレージのシリアルコンテナ挿入/消去メンバー関数のパラメータがreverse_iteratorにすることはできず、他のすべてはOKであり、イテレータとconst_iteratorの比較、算術演算を除いて、テストを実行しました、など。

    void iteratorTest1() {
        vector<int> vec{0, 0, 1, 2, 3, 4};

        // erase和insert成员函数中对迭代器类型的要求
        vec.erase(vec.begin()); // right
        vec.erase(vec.cbegin()); // right
        // vec.erase(vec.rbegin()); // ERROR reverse iterator 不能作为erase的参数

        vec.insert(vec.end(), 5); // right, vec{1,2,3,4,5}
        vec.insert(vec.cend(), 6); // right, vec{1,2,3,4,5,6}
        // vec.insert(vec.rbegin(), 5); // ERROR reverse iterator 不能作为insert的参数

        // iterator 与 const_iterator 比较
        auto iter = vec.begin();
        auto citer = vec.cbegin();
        if (iter == citer || citer == iter) {
            // 为啥两个不同的迭代器类型可以比较呢,应该是iterator隐式转换为const_iterator了
            // 实质上是两个const_iterator之间的比较
            cout << "iterator can be compared with const_iterator" << endl;
        }

        std::advance(iter, 3); // 将iter向前累加3个位置
        if (iter - citer >= 3 || citer + 3 <= iter) {
            // iterator与const_iterator之间能进行算术运算
            cout << "iterator can be operator with const_iterator" << endl;
        }

        return;
    }

 

アイテム27:距離と前進を使用して、コンテナーのconst_iteratorをイテレーターに変換します

最新のC ++コンパイラのほとんどは直接変換でき、句の複雑なプラクティスは必要ありませんが、本のプラクティスは間違いなく移植可能です

    void iteratorTest2() {
        // vector/string可以
        vector<int> vec{1, 2, 3, 4, 5};
        auto citer1 = vec.cbegin();
        auto iter1 = citer1; // 可以转换
        cout << *iter1 << endl;
        std::advance(iter1, std::distance(iter1, citer1)); // 也OK,但是没必要这么复杂,上面的直接转换就可以
        cout << *iter1 << endl;

        // deque/list/set/map/unordered_set等
        std::deque<int> dq{1, 2, 3, 4, 5};
        auto citer2 = dq.cbegin();
        auto iter2 = citer2; // 可以转换
        cout << *iter2 << endl;
        std::advance(iter2, std::distance(iter2, citer2 + 2)); // 也OK,但是没必要这么复杂,上面的直接转换就可以
        cout << *iter2 << endl;

        std::list<int> ls{1, 2, 3, 4, 5};
        auto citer3 = ls.cbegin();
        auto iter3 = citer3; // 可以转换
        cout << *iter3 << endl;
        std::advance(iter3, std::distance(iter3, citer3)); // 也OK,但是没必要这么复杂,上面的直接转换就可以
        cout << *iter3 << endl;

        std::map<int, int> mp{
   
   {1, 2}, {2, 3}};
        auto citer4 = mp.cbegin();
        auto iter4 = citer4; // 可以转换
        cout << iter4->first << ", " << iter4->second << endl;
        std::advance(iter4, std::distance(iter4, citer4)); // 也OK,但是没必要这么复杂,上面的直接转换就可以
        cout << iter4->first << ", " << iter4->second << endl;


        std::unordered_set<int> ust{1,2,3,4,5};
        auto citer5 = ust.cbegin();
        auto iter5 = citer5;
        cout << *iter5 << endl; // 可以转换
        std::advance(iter5, std::distance(iter5, citer5)); // 也OK,但是没必要这么复杂,上面的直接转换就可以
        cout << *iter5 << endl;

        // 下面是条款中介绍的做法,这个做法肯定具有可移植性,但是稍显复杂
        using ConstIter = std::unordered_set<int>::const_iterator;
        std::advance(iter5, std::distance<ConstIter>(iter5, citer5));

        return;
    }

 

項目28:reverse_iteratorのbase()メンバー関数によって生成されたイテレータの使用法を正しく理解する

   void iteratorTest3() {
        vector<int> vec{1, 2, 3, 4, 5};
        auto riter1 = std::find(vec.rbegin(), vec.rend(), 3);
        cout << "*riter1: " << *riter1 << endl;  // 3
        auto iter1 = riter1.base();
        cout << "*iter1: " << *iter1 << endl;  // 4

        auto riter2 = vec.rbegin() + 2;
        cout << "*riter2: " << *riter2 << endl;  // 3
        auto iter2 = riter2.base();
        cout << "*iter2: " << *iter2 << endl;  // 4

        // 插入数据,行为是一致的
        // vec.insert(riter2, 99); // 实际上不能用reverse_iterator作为参数,这儿假设能插入,则结果入下{1, 2, 3, 99, 4, 5}
        iter2 = vec.insert(iter2, 99); // vec = {1, 2, 3, 99, 4, 5}
        cout << *iter2 << endl;

        // 如果是删除数据,则行为不一致,需要特别注意,这个时候两者不是指向同一个元素
        auto riter3 = vec.rbegin() + 2;
        cout << "*riter3: " << *riter3 << endl;  // 99
        auto iter3 = riter3.base();
        cout << "*iter3: " << *iter3 << endl;  // 4
        // vec.erase(--riter3.base()); // 成功删除99, 但是某些编译器可能无法通过编译,因为C++规定从函数返回的指针不应该被修改
        // vec.erase(--iter3); // 成功删除99
        vec.erase((++riter3).base()); // 书中推荐的做法,成功删除99

        return;
    }

 

項目29:文字ごとの入力については、istreambuf_iteratorの使用を検討してください

istream_iteratorは、演算子>>を使用して、入力ストリームから1文字を読み取ります。これには、多くのフォーマット操作が含まれます。デフォルトでは、関数は空白文字をスキップします。

istreambuf_iteratorは、フォーマットせずにストリームのバッファーから直接次の文字を読み取り、文字をスキップしません。

    void iteratorTest4() {
        // istream_iterator
        // 从输入流中读取单个字符
        // 默认使用operator>>,涉及格式化等操作,效率不高,而且会忽略空白字符
        std::ifstream ifs1;
        ifs1.open("EnData.txt");
        std::string fileData1;
        if (ifs1.is_open()) {
            fileData1.append((std::istream_iterator<char>(ifs1)), std::istream_iterator<char>());
        }

        // istreambuf_iterator
        // 适用于非格式化的逐个字符输入过程
        // 直接从流的缓冲区中读取下一个字符,效率更高,且不会跳过任何字符
        std::ifstream ifs2;
        ifs2.open("EnData.txt");
        std::string fileData2;
        if (ifs2.is_open()) {
            fileData2.append((std::istreambuf_iterator<char>(ifs2)), std::istreambuf_iterator<char>());
        }

        return;
    }

デバッグのスクリーンショット

参考:「効果的なSTL中国語版」

おすすめ

転載: blog.csdn.net/u010323563/article/details/112757610