代码之家  ›  专栏  ›  技术社区  ›  Adrian McCarthy

通过引用传递C++迭代器有什么不对?

  •  36
  • Adrian McCarthy  · 技术社区  · 16 年前

    template <typename input_iterator>
    int parse_integer(input_iterator &begin, input_iterator end);
    

    begin 在最后使用的字符的一个过去。例如:

    std::string sample_text("123 foo bar");
    std::string::const_iterator p(sample_text.begin());
    std::string::const_iterator end(sample_text.end());
    int i = parse_integer(p, end);
    

    这将离开 i 设置为123和 p “指向”前面的空间 foo .

    7 回复  |  直到 5 年前
        1
  •  36
  •   Johannes Schaub - litb    16 年前

    没有什么真正的错误,但它肯定会限制模板的使用。您不能只放置由其他对象返回或生成的迭代器,如 v.begin()

    一种方法是使其过载:

    int parse_integer(input_iterator begin, input_iterator end, 
                      input_iterator &newbegin);
    
    template<typename input_iterator>
    int parse_integer(input_iterator begin, input_iterator end) {
        return parse_integer(begin, end, begin);
    } 
    

    另一个选项是使用输出迭代器,其中数字将写入:

    template<typename input_iterator, typename output_iterator>
    input_iterator parse_integer(input_iterator begin, input_iterator end,
                                 output_iterator out);
    

    您将有返回值来返回新的输入迭代器。然后可以使用插入器迭代器将解析后的数字放入向量或指针中,直接放入整数或其数组中(如果您已经知道数字的数量)。

    int i;
    b = parse_integer(b, end, &i);
    
    std::vector<int> numbers;
    b = parse_integer(b, end, std::back_inserter(numbers));
    
        2
  •  5
  •   Reunanen    16 年前

    一般来说:

    const 调用方不知道迭代器是否正在被修改。

    你可以通过考试 常数 引用,但通常迭代器足够小,与按值传递相比没有任何优势。

    我不认为您所做的有任何错误,除了迭代器的使用不太标准。

        3
  •  2
  •   ChrisW    16 年前

    然而,在本例中,您需要返回两个值:解析的int值和新的/修改的迭代器值;假设一个函数不能有两个返回码,将其中一个返回码编码为非常量引用是很正常的。

    另一种方法是将其编码如下:

    //Comment: the return code is a pair of values, i.e. the parsed int and etc ...
    pair<int, input_iterator> parse(input_iterator start, input_iterator end)
    {
    }
    
        4
  •  2
  •   Community CDub    8 年前

    在我看来,如果你想这样做,参数应该是一个指向你将要更改的迭代器的指针。我不太喜欢非常量引用参数,因为它们隐藏了传递的参数可能会更改的事实。我知道有很多C++用户不同意我的观点,这很好。

    然而,在这种情况下,它是 所以

    既然有一种很好的方法可以做你想做的事情,而不存在这个问题,我认为你应该使用它:

    template <typename input_iterator>
    int parse_integer(input_iterator* begin, input_iterator end);
    

    现在,呼叫方必须执行以下操作:

    int i = parse_integer(&p, end);
    

    很明显,迭代器是可以更改的。

    litb's suggestion 返回新迭代器并将解析后的值放入输出迭代器指定的位置。

        5
  •  2
  •   Edward Loper    13 年前

    值得注意的是,您的方法(通过引用传递迭代器以跟踪标记流时的位置)正是 boost::tokenizer . 具体请参见 TokenizerFunction Concept

        6
  •  1
  •   anon anon    16 年前

    我认为标准库算法只通过值传递迭代器(现在有人会发布一个明显的例外)——这可能是这个想法的起源。当然,没有人说您自己的代码必须看起来像标准库!

        7
  •  -1
  •   dirkgently    16 年前

    函数声明的第二个参数缺少引用,是吗?

    无论如何,回到你的问题:不,我从来没有读过任何东西说你不应该通过引用传递迭代器。引用的问题是,它们允许您更改引用的对象。在这种情况下,如果要更改迭代器,则可能会将整个序列弄糟,超出该点,从而导致无法进行进一步处理。

    只有一个建议:仔细输入参数。