Item13 Prefer const_iterators to iterators

   const_iterator 是STL提供的一个等同于const指针的东西,并且它所指向的值是不可变的。标准实践中,当你需要迭代器并且不需要更改迭代器指向的值的时候,你应该使用const_iterator,无论是在C++98,还是C++11,这个标准实践都是正确的,可是在C++98中是并不完全支持const_iterator。什么叫不完全支持呢?

   例如,STL是有const_iterator类型的迭代器,但是没有办法创建一个const_iterator迭代器。容器类型只提供了begin(),end()等返回iterator的成员方法,std::find返回的也是非常量版本的迭代器。或许有人认为可以通过static_cast转化一下,所以有了下面这段代码:

typedef std::vector<int>::iterator IterT;
typedef std::vector<int>::const_iterator ConstIterT;


int main() {
  std::vector<int> values;
  ConstIterT ci = std::find(values.begin(),values.end(),198);
  values.insert(static_cast<IterT>(ci), 198);
  return 0;
}

   上面的代码中std::find返回的是非常量的迭代器,因为后续不会改动,遵从标准实践我通过static_cast将其转化为常量迭代器,而当我在要往这个迭代器出插入一个元素的时候,我又不得不把它转换为非常量的迭代器,因为insert的接受的就是非常量的迭代器,为此我又再次使用了神兵利器static_cast ,可是这次失败了,因为这是一个不可逆的转换,随后我尝试用reinterpret_cast,const_cast都不行。
   不过这一问题在C++11中得以解决,在C++11中可以很轻松的创建和使用常量迭代器,它给容器都提供了cbegincend等成员函数用于返回常量迭代器,修改容器中像insert这种通过传递迭代器来标识位置的成员函数都修改成传递常量迭代器的版本。在C++11中上面的代码可以更改成下面的形式:

int main() {
  std::vector<int> values;
  auto it = std::find(values.cbegin(),values.cend(),198);
  values.insert(it, 198);
  return 0;
}

到此为止可以使用常量迭代器实现标准实践了。

​   虽然C++11提供了返回常量迭代器的成员函数cbegincend,但是这并不通用,因为除了标准容器外,其实还有一些类似于容器的数据结构,这些结构没有beginend等这类方法,为此C++11中提供了非成员函数的版本,可以用于像数组这种类容器的数据结构。只有非成员函数版本的beginend,对于写一些通用代码就更加的方便了。

template <typename C, typename V>
  void findAndInsert(C& container,
                     const V& targetVal,
                     const V& insertVal)
  {
    using std::cbegin;
    using std::end;

    auto it = std::find(cbegin(container), cend(container), targetVal);
    container.insert(it, insertVal);
  }

   上面的代码就比较通用了,对于一切类容器的数据结构都是适用的,而不是只能用于标准的STL容器了。很可惜上面的代码需要C++14的支持,C++11只支持beginend,而到C++14才开始支持cbegincend。如果你的编译器不支持C++14,那么你可以使用下面这段代码代替。

template <typename C>
auto cbegin(const C& container)->decltype(std::begin(container))
{
  return std::begin(container);
}

上面这段代码的实现,巧妙了利用了模版类型推导的原则,具体可以参见Item1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值