关于 std::unique 实现的困惑?

Nic*_*den 5 c++ stl stl-algorithm

根据这篇文章,一种可能的实现std::unique

template<class ForwardIt>
ForwardIt unique(ForwardIt first, ForwardIt last)
{
    if (first == last)
        return last;

    ForwardIt result = first;
    while (++first != last) {
        if (!(*result == *first) && ++result != first) {
            *result = std::move(*first);
        }
    }
    return ++result;
}
Run Code Online (Sandbox Code Playgroud)

但是,我不明白迭代器比较的用途是什么?为什么if (!(*result == *first) && ++result != first)而不只是if (!(*result++ == *first))?比较两个迭代器的目的是什么?

Jer*_*iah 5

让我们将代码重写为更小的步骤(代码相当于问题中的代码 - 我刚刚将 if 语句拆分为两个单独的部分):

template<class ForwardIt>
ForwardIt unique(ForwardIt first, ForwardIt last)
{
    // are there elements to test?
    if (first == last)
        return last;

    // there are elements so point result to the first one
    ForwardIt result = first;

    // then increment first and check if we are done
    while (++first != last) {

        // if the value of first is still the same as the value of result
        // then restart the loop (incrementing first and checking if we are done)
        // Notice that result isn't moved until the values differ
        if (*result == *first)
            continue;

        // increment result and move the value of first to this new spot
        // as long as they don't point to the same place
        // So result is only moved when first points to a new (different) value 
        if (++result != first) {
            *result = std::move(*first);
        }
    }

    // return one past the end of the new (possibly shorter) range.
    return ++result;
}
Run Code Online (Sandbox Code Playgroud)

下面是一个例子:

result
   v
+-----+-----+-----+-----+-----+-----+-----+-----+
|  1  |  2  |  2  |  3  |  4  |  4  |  4  |  5  |
+-----+-----+-----+-----+-----+-----+-----+-----+
   ^                                               ^
 first                                           last
Run Code Online (Sandbox Code Playgroud)

步骤 1 - 先递增并将 first 的值与结果的值进行比较:

result
   v
+-----+-----+-----+-----+-----+-----+-----+-----+
|  1  |  2  |  2  |  3  |  4  |  4  |  4  |  5  |
+-----+-----+-----+-----+-----+-----+-----+-----+
         ^                                         ^
       first                                      last
Run Code Online (Sandbox Code Playgroud)

第 2 步 - 值不同,所以增加结果,但现在它们指向同一个地方,所以移动是多余的,我们不这样做

      result
         v
+-----+-----+-----+-----+-----+-----+-----+-----+
|  1  |  2  |  2  |  3  |  4  |  4  |  4  |  5  |
+-----+-----+-----+-----+-----+-----+-----+-----+
         ^                                         ^
       first                                      last
Run Code Online (Sandbox Code Playgroud)

第 3 步 - 先递增并将 first 的值与结果的值进行比较:

      result
         v
+-----+-----+-----+-----+-----+-----+-----+-----+
|  1  |  2  |  2  |  3  |  4  |  4  |  4  |  5  |
+-----+-----+-----+-----+-----+-----+-----+-----+
               ^                                   ^
             first                                last
Run Code Online (Sandbox Code Playgroud)

第 4 步 - 值相同,因此重新启动循环(首先递增并将 first 的值与结果的值进行比较):

      result
         v
+-----+-----+-----+-----+-----+-----+-----+-----+
|  1  |  2  |  2  |  3  |  4  |  4  |  4  |  5  |
+-----+-----+-----+-----+-----+-----+-----+-----+
                     ^                             ^
                   first                          last
Run Code Online (Sandbox Code Playgroud)

第 5 步 - 值不同,因此增加结果,它们指向不同的位置,因此将 first 的值移动到 result 的值中:

            result
               v
+-----+-----+-----+-----+-----+-----+-----+-----+
|  1  |  2  |  3  |  3  |  4  |  4  |  4  |  5  |
+-----+-----+-----+-----+-----+-----+-----+-----+
                     ^                             ^
                   first                          last
Run Code Online (Sandbox Code Playgroud)

第 6 步 - 先递增并将 first 的值与结果的值进行比较:

            result
               v
+-----+-----+-----+-----+-----+-----+-----+-----+
|  1  |  2  |  3  |  3  |  4  |  4  |  4  |  5  |
+-----+-----+-----+-----+-----+-----+-----+-----+
                           ^                       ^
                         first                    last
Run Code Online (Sandbox Code Playgroud)

第 7 步 - 值不同,因此增加结果,它们指向不同的位置,因此将 first 的值移动到 result 的值中:

                  result
                     v
+-----+-----+-----+-----+-----+-----+-----+-----+
|  1  |  2  |  3  |  4  |  4  |  4  |  4  |  5  |
+-----+-----+-----+-----+-----+-----+-----+-----+
                           ^                       ^
                         first                    last
Run Code Online (Sandbox Code Playgroud)

第 8 步 - 先递增并将 first 的值与结果的值进行比较:

                  result
                     v
+-----+-----+-----+-----+-----+-----+-----+-----+
|  1  |  2  |  3  |  4  |  4  |  4  |  4  |  5  |
+-----+-----+-----+-----+-----+-----+-----+-----+
                                 ^                 ^
                               first              last
Run Code Online (Sandbox Code Playgroud)

第 9 步 - 值相同,因此重新启动循环(首先递增并将 first 的值与结果的值进行比较):

                  result
                     v
+-----+-----+-----+-----+-----+-----+-----+-----+
|  1  |  2  |  3  |  4  |  4  |  4  |  4  |  5  |
+-----+-----+-----+-----+-----+-----+-----+-----+
                                       ^           ^
                                     first        last
Run Code Online (Sandbox Code Playgroud)

第 10 步 - 值相同,因此重新启动循环(首先递增并将 first 的值与结果的值进行比较):

                  result
                     v
+-----+-----+-----+-----+-----+-----+-----+-----+
|  1  |  2  |  3  |  4  |  4  |  4  |  4  |  5  |
+-----+-----+-----+-----+-----+-----+-----+-----+
                                             ^     ^
                                           first  last
Run Code Online (Sandbox Code Playgroud)

第 11 步 - 值不同,因此增加结果,它们指向不同的地方,因此将 first 的值移动到 result 的值中:

                        result
                           v
+-----+-----+-----+-----+-----+-----+-----+-----+
|  1  |  2  |  3  |  4  |  5  |  4  |  4  |  5  |
+-----+-----+-----+-----+-----+-----+-----+-----+
                                             ^      ^
                                           first   last
Run Code Online (Sandbox Code Playgroud)

第 12 步 - 首先递增,while 循环结束,因为 first 和 last 指向同一个位置 - 然后在循环递增结果之后,它成为唯一范围的新结束迭代器:

                              result
                                 v
+-----+-----+-----+-----+-----+-----+-----+-----+
|  1  |  2  |  3  |  4  |  5  |  4  |  4  |  5  |
+-----+-----+-----+-----+-----+-----+-----+-----+
                                                    ^
                                                last&first
Run Code Online (Sandbox Code Playgroud)