繁体   English   中英

C++ STL 中的 const_iterator 和非常量迭代器有什么区别?

[英]What is the difference between const_iterator and non-const iterator in the C++ STL?

const_iteratoriterator之间有什么区别,你会在哪里使用一个而不是另一个?

const_iterator不允许您更改它们指向的值,常规iterator可以。

与 C++ 中的所有内容一样,总是更喜欢const ,除非有充分的理由使用常规迭代器(即您想使用它们不是const来更改指向值的事实)。

它们应该是不言自明的。 如果 iterator 指向类型为 T 的元素,则 const_iterator 指向类型为“const T”的元素。

它基本上等同于指针类型:

T* // A non-const iterator to a non-const element. Corresponds to std::vector<T>::iterator
T* const // A const iterator to a non-const element. Corresponds to const std::vector<T>::iterator
const T* // A non-const iterator to a const element. Corresponds to std::vector<T>::const_iterator

const 迭代器总是指向同一个元素,所以迭代器本身是 const 的。 但是它指向的元素不一定是const,所以它指向的元素是可以改变的。 const_iterator 是指向 const 元素的迭代器,因此虽然迭代器本身可以更新(例如递增或递减),但它指向的元素不能更改。

不幸的是,STL 容器的很多方法都使用迭代器而不是const_iterator作为参数。 所以如果你有一个const_iterator ,你不能说“在这个迭代器指向的元素之前插入一个元素”(在我看来,说这样的事情在概念上并不是const违规)。 如果您无论如何都想这样做,则必须使用std::advance()boost::next()将其转换为非常量迭代器。 例如。 boost::next(container.begin(), std::distance(container.begin(), the_const_iterator_we_want_to_unconst)) 如果容器std::list ,则该调用的运行时间将为O(n)

因此,在“合乎逻辑”的地方添加 const 的通用规则在 STL 容器方面不太通用。

但是,boost 容器采用 const_iterators(例如 boost::unordered_map::erase())。 因此,当您使用 boost 容器时,您可能会变得“具有攻击性”。 顺便说一句,有谁知道 STL 容器是否或何时修复?

尽可能使用const_iterator ,在别无选择时使用iterator

最小的可运行示例

非常量迭代器允许您修改它们指向的内容:

std::vector<int> v{0};
std::vector<int>::iterator it = v.begin();
*it = 1;
assert(v[0] == 1);

Const 迭代器不会:

const std::vector<int> v{0};
std::vector<int>::const_iterator cit = v.begin();
// Compile time error: cannot modify container with const_iterator.
//*cit = 1;

如上所示, v.begin()const重载的,并根据容器变量的常量性返回iteratorconst_iterator

const_iterator弹出的常见情况是在const方法中使用this时:

class C {
    public:
        std::vector<int> v;
        void f() const {
            std::vector<int>::const_iterator it = this->v.begin();
        }
        void g(std::vector<int>::const_iterator& it) {}
};

const使this const成为常量,这使得this->v常量。

您通常可以使用auto忘记它,但是如果您开始传递这些迭代器,您将需要考虑它们的方法签名。

与常量和非常量非常相似,您可以轻松地从非常量转换为常量,但不能反过来:

std::vector<int> v{0};
std::vector<int>::iterator it = v.begin();

// non-const to const.
std::vector<int>::const_iterator cit = it;

// Compile time error: cannot modify container with const_iterator.
//*cit = 1;

// Compile time error: no conversion from const to no-const.
//it = ci1;

使用哪一个:类似于const intint :只要可以使用 const 迭代器(当您不需要用它们修改容器时),就更喜欢使用它们,以更好地记录您的阅读意图而无需修改。

(正如其他人所说) const_iterator 不允许您修改它指向的元素,这在 const 类方法中很有用。 它还允许您表达您的意图。

好的让我先用非常简单的例子来解释它而不使用常量迭代器考虑我们有随机整数集合“randomData”的集合

    for(vector<int>::iterator i = randomData.begin() ; i != randomData.end() ; ++i)*i = 0;
for(vector<int>::const_iterator i = randomData.begin() ; i!= randomData.end() ; ++i)cout << *i;

可以看出,在集合内部写入/编辑数据时,使用了普通迭代器,但出于读取目的,使用了常量迭代器。 如果您尝试在第一个 for 循环中使用常量迭代器,则会出现错误。 作为一个经验法则,使用常量迭代器来读取 collection 中的数据。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM