C++ 更喜欢迭代器而不是指针?

C++ 更喜欢迭代器而不是指针?,c++,string,iterator,char-pointer,const-pointer,C++,String,Iterator,Char Pointer,Const Pointer,是一个问题的凹凸,该问题有注释,但作为凹凸的一部分被删除 对于那些看不到已删除帖子的人,我的评论是关于我使用const char*s而不是string::const_迭代器s in:“迭代器可能从一开始就是一个更好的路径,因为它似乎正是您的指针的处理方式。” 所以我的问题是,迭代器是否持有string::const_迭代器s持有const char*s上的任何内在值,这样将我的答案切换到string::const_迭代器就有意义了?引言 使用迭代器而不是指针有很多好处,其中包括: 版本与调试中

是一个问题的凹凸,该问题有注释,但作为凹凸的一部分被删除

对于那些看不到已删除帖子的人,我的评论是关于我使用
const char*
s而不是
string::const_迭代器
s in:“迭代器可能从一开始就是一个更好的路径,因为它似乎正是您的指针的处理方式。”

所以我的问题是,迭代器是否持有
string::const_迭代器
s持有
const char*
s上的任何内在值,这样将我的答案切换到
string::const_迭代器
就有意义了?

引言 使用迭代器而不是指针有很多好处,其中包括:

  • 版本与调试中的不同代码路径,以及
  • 更好的类型安全性,以及
  • 使编写通用代码成为可能(迭代器可以用于任何数据结构,如链表,而内在指针在这方面非常有限)


调试 因为,除其他事项外,取消引用传递到范围末尾的迭代器是未定义的行为,因此实现可以自由地执行在这种情况下认为必要的任何操作,包括提出诊断,指出您做错了什么

gcc提供的标准库实现在检测到故障时(如果启用)将发出诊断


示例

如果我们使用指针,无论是否处于调试模式,上述情况都不会发生

如果我们不为libstdc++启用调试模式,将使用性能更友好的版本(没有添加簿记)实现,并且不会发布诊断



(可能)更好的类型安全性 由于迭代器的实际类型是由实现定义的,因此可以使用它来提高类型安全性,但是您必须检查实现的文档,以确定是否是这样


考虑以下示例:

#include <vector>

/.--oops
//五
void it_func(std::vector::iterator beg,std::vector::iterator end);
void ptr_func(B*beg,A*end);
//^--哎呀

int
main(int argc,char*argv[])
{
std::向量v1;
it_func(v1.begin(),v1.end());/(A)
ptr_func(v1.data(),v1.data()+v1.size());/(B)
}
精化

  • (A) 根据实现的不同,可能是编译时错误,因为
    std::vector::iterator
    std::vector::iterator
    可能不是同一类型
  • (B) 但是,将始终编译,因为存在从
    B*
    A*
    的隐式转换

迭代器旨在提供指针上的抽象

例如,递增迭代器总是操纵迭代器,因此如果集合中有下一项,它将引用该下一项。如果它已经引用了集合中的最后一个项,则在增量之后,它将是一个唯一的值,不能取消引用,但将与指向同一集合末尾的另一个迭代器(通常通过
collection.end()
)进行比较

在将迭代器转换为字符串(或向量)的特定情况下,指针提供了迭代器所需的所有功能,因此指针可以用作迭代器,而不会丢失所需的功能

例如,可以使用
std::sort
对字符串或向量中的项进行排序。由于指针提供了所需的功能,因此还可以使用它对本机(C样式)数组中的项进行排序

同时,是的,定义(或使用)一个独立于指针的迭代器可以提供不严格要求的额外功能。例如,某些迭代器提供至少某种程度的检查,以确保(例如)在比较两个迭代器时,它们都是同一集合中的迭代器,并且您没有尝试越界访问。原始指针不能(或至少通常不会)提供这种功能

这在很大程度上源于“不要为你不用的东西付费”的心态。如果您真的只需要并且想要本机指针的功能,那么它们可以用作迭代器,您通常会得到与直接操作指针基本相同的代码。同时,对于需要额外功能的情况,例如遍历线程RB树或B+树而不是简单数组,迭代器允许您在维护单个简单接口的同时执行此操作。同样,如果您不介意为额外的安全性支付额外费用(在存储和/或运行时方面),您也可以获得额外的安全性(而且它与诸如单个算法之类的东西是解耦的,因此您可以在您想要的地方获得它,而不必被迫在其他地方使用它,例如,可能对时间要求太苛刻而无法支持它

在我看来,很多人在使用迭代器时都忽略了这一点。很多人都乐于重写如下内容:

for (size_t i=0; i<s.size(); i++)
for (std::string::iterator i = s.begin; i != s.end(); i++)
…并表现得好像这是一项重大成就。我不认为是。在这种情况下,用迭代器替换整数类型可能没有什么好处(如果有的话)。同样地,将您发布的代码更改为
char const*
std::string::iterator
似乎不太可能实现多少(如果有的话).事实上,这种转换通常会使代码更冗长,更难理解,但却没有得到任何回报

如果您打算更改代码,您应该(在我看来)这样做,通过使其真正通用(即
std::string::iterator
                                                      // .-- oops
                                                      // v
void  it_func (std::vector<B>::iterator beg, std::vector<A>::iterator end);

void ptr_func (B * beg, A * end);
                     // ^-- oops
int
main (int argc, char *argv[])
{
  std::vector<B> v1;

   it_func (v1.begin (), v1.end  ());               // (A)
  ptr_func (v1.data  (), v1.data () + v1.size ());  // (B)
}
for (size_t i=0; i<s.size(); i++)
for (std::string::iterator i = s.begin; i != s.end(); i++)
vector<string> split(const char* start, const char* finish){
    const char delimiters[] = ",(";
    const char* it;
    vector<string> result;

    do{
        for (it = find_first_of(start, finish, begin(delimiters), end(delimiters));
            it != finish && *it == '(';
            it = find_first_of(extractParenthesis(it, finish) + 1, finish, begin(delimiters), end(delimiters)));
        auto&& temp = interpolate(start, it);
        result.insert(result.end(), temp.begin(), temp.end());
        start = ++it;
    } while (it <= finish);
    return result;
}
template <class InIt, class OutIt, class charT>
void split(InIt start, InIt finish, charT paren, charT comma, OutIt result) {
    typedef std::iterator_traits<OutIt>::value_type o_t;
    charT delimiters[] = { comma, paren };
    InIt it;

    do{
        for (it = find_first_of(start, finish, begin(delimiters), end(delimiters));
            it != finish && *it == paren;
            it = find_first_of(extractParenthesis(it, finish) + 1, finish, begin(delimiters), end(delimiters)));
        auto&& temp = interpolate(start, it);
        *result++ = o_t{temp.begin(), temp.end()};
        start = ++it;
    } while (it != finish);
}