Iterators (Chapter 4) (items 26, 27, 28, 29)

 

Special note: The C++11 standard has not been released when the author writes this book. There are some differences in the implementation of the C++ standard by different compiler manufacturers, which leads to some of the content of the book now and the latest C++ standard and the behavior of most compilers. Please pay special attention to the difference.

Item 26: Iterator takes precedence over const_iterator, reverse_iterator, const_reverse_iterator

For the examples mentioned in the book, I conducted a test, except that the parameter of the serial container insert/erase member function of continuous storage cannot be reverse_iterator, everything else is OK, as well as comparison between iterator and const_iterator, arithmetic operations, etc.

    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;
    }

 

Item 27: Use distance and advance to convert the container's const_iterator to iterator

Most of the modern C++ compilers can be directly converted, and there is no need for the complicated practices in the clauses, but the practices in the book are definitely portable

    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;
    }

 

Item 28: Correctly understand the usage of iterator generated by the base() member function of reverse_iterator

   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;
    }

 

Item 29: For character-by-character input, please consider using istreambuf_iterator

istream_iterator is to use operator>> to read a single character from the input stream, which involves many formatting operations. By default, the function skips whitespace characters;

istreambuf_iterator reads the next character directly from the buffer of the stream, without formatting, and will not skip any characters;

    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;
    }

Debug screenshot

Reference: "Effective STL Chinese Version"

Guess you like

Origin blog.csdn.net/u010323563/article/details/112757610