对 std::唯一实现感到困惑?
Confusion about std::unique implementation?
根据本文,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;
}
但是,我不明白迭代器比较的用途是什么?为什么if (!(*result == *first) && ++result != first)
而不仅仅是if (!(*result++ == *first))
?比较两个迭代器的目的是什么?
让我们将代码重写为更小的步骤(代码等效于问题中的代码 - 我刚刚将 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;
}
下面是一个示例:
result
v
+-----+-----+-----+-----+-----+-----+-----+-----+
| 1 | 2 | 2 | 3 | 4 | 4 | 4 | 5 |
+-----+-----+-----+-----+-----+-----+-----+-----+
^ ^
first last
步骤1 - 先递增,并将第一个的值与结果的值进行比较:
result
v
+-----+-----+-----+-----+-----+-----+-----+-----+
| 1 | 2 | 2 | 3 | 4 | 4 | 4 | 5 |
+-----+-----+-----+-----+-----+-----+-----+-----+
^ ^
first last
步骤2 - 值不同,因此增量结果,但现在它们指向同一位置,因此移动是多余的,我们不这样做
result
v
+-----+-----+-----+-----+-----+-----+-----+-----+
| 1 | 2 | 2 | 3 | 4 | 4 | 4 | 5 |
+-----+-----+-----+-----+-----+-----+-----+-----+
^ ^
first last
步骤3 - 首先递增并将第一个的值与结果的值进行比较:
result
v
+-----+-----+-----+-----+-----+-----+-----+-----+
| 1 | 2 | 2 | 3 | 4 | 4 | 4 | 5 |
+-----+-----+-----+-----+-----+-----+-----+-----+
^ ^
first last
步骤4 - 值相同,因此重新启动循环(首先递增并将第一个的值与结果的值进行比较(:
result
v
+-----+-----+-----+-----+-----+-----+-----+-----+
| 1 | 2 | 2 | 3 | 4 | 4 | 4 | 5 |
+-----+-----+-----+-----+-----+-----+-----+-----+
^ ^
first last
步骤5 - 值不同,因此递增结果,它们指向不同的地方,因此将第一个的值移动到结果的值:
result
v
+-----+-----+-----+-----+-----+-----+-----+-----+
| 1 | 2 | 3 | 3 | 4 | 4 | 4 | 5 |
+-----+-----+-----+-----+-----+-----+-----+-----+
^ ^
first last
步骤6 - 先递增,并将第一个的值与结果的值进行比较:
result
v
+-----+-----+-----+-----+-----+-----+-----+-----+
| 1 | 2 | 3 | 3 | 4 | 4 | 4 | 5 |
+-----+-----+-----+-----+-----+-----+-----+-----+
^ ^
first last
步骤7 - 值不同,因此递增结果,它们指向不同的地方,因此将第一个的值移动到结果的值:
result
v
+-----+-----+-----+-----+-----+-----+-----+-----+
| 1 | 2 | 3 | 4 | 4 | 4 | 4 | 5 |
+-----+-----+-----+-----+-----+-----+-----+-----+
^ ^
first last
步骤8 - 先递增,并将第一个的值与结果的值进行比较:
result
v
+-----+-----+-----+-----+-----+-----+-----+-----+
| 1 | 2 | 3 | 4 | 4 | 4 | 4 | 5 |
+-----+-----+-----+-----+-----+-----+-----+-----+
^ ^
first last
步骤9 - 值相同,因此重新启动循环(首先递增并将第一个的值与结果的值进行比较(:
result
v
+-----+-----+-----+-----+-----+-----+-----+-----+
| 1 | 2 | 3 | 4 | 4 | 4 | 4 | 5 |
+-----+-----+-----+-----+-----+-----+-----+-----+
^ ^
first last
步骤10 - 值相同,因此重新启动循环(先递增并将第一个的值与结果的值进行比较(:
result
v
+-----+-----+-----+-----+-----+-----+-----+-----+
| 1 | 2 | 3 | 4 | 4 | 4 | 4 | 5 |
+-----+-----+-----+-----+-----+-----+-----+-----+
^ ^
first last
步骤11 - 值不同,因此递增结果,它们指向不同的地方,因此将第一个的值移动到结果的值:
result
v
+-----+-----+-----+-----+-----+-----+-----+-----+
| 1 | 2 | 3 | 4 | 5 | 4 | 4 | 5 |
+-----+-----+-----+-----+-----+-----+-----+-----+
^ ^
first last
步骤 12 - 先递增,while 循环结束,因为第一个和最后一个指向同一位置 - 然后在循环增量结果之后,它成为唯一范围的新结束迭代器:
result
v
+-----+-----+-----+-----+-----+-----+-----+-----+
| 1 | 2 | 3 | 4 | 5 | 4 | 4 | 5 |
+-----+-----+-----+-----+-----+-----+-----+-----+
^
last&first
如果你这样做if(!(*result++ == *first))
你总是在你的状况中增加result
。但是,如果!(*result == *first)
是假的,则由于短路评估,条件的第二部分永远不会得到评估。
差异对于"独特"的含义至关重要。
ForwardIt result = first;
while (++first != last) {
if (!(*result == *first) && ++result != first) {
*result = std::move(*first);
}
}
return ++result;
可以改写为
ForwardIt result = first;
// result is the last element different from previous values
// all the equal elements after result=first are useless
// *result = *first
// first is the last element examined
// determine largest range of useless elements
// *result = before(*first)
// i.e. result has the value of former value (before call) of element *first (current value of first)
// so first is the last element on which we know something
extend_useless_range:
// so range ]result,first] is useless
first++;
// now range ]result,first[ is useless
// and first is the first element yet to be examined
if (first == last) {
// ]result,last[ is useless
goto end_loop;
}
if (*result == *first) {
// *first is useless
// so range ]result,first] is useless
goto extend_useless_range;
}
// *first is useful
// range ]result,first[ is biggest useless range after result
result++;
// range [result,first[ is useless (and *first is useful)
if (result != first) {
// [result,first[ is nonempty
*result = std::move(*first);
// *result is useful and *first is useless (undetermined value)
// ]result,first] is useless
}
else {
// [result,first[ = ]result,first] = {} and is useless
}
// ]result,first] is useless
goto extend_useless_range;
end_loop: // ]result,last[ is useless
result++;
// [result,last[ is useless
return result;
- C++标准是否允许<double>在没有开销的情况下实现 std::可选
- glibcxx STL 在实现 std::valarray::sum() 时是否不正确?
- 在 x86 上实现 std::atomic_thread_fence(std::memory_order_seq_cst
- 尝试实现std::tie和std::tuple的小版本
- 在实现 std::vector 时,我必须拥有 end() 的"end"指针吗?
- 如何正确实现 std::all_of 函数来验证字符串的一部分?
- 如何为向量实现 std::erase ?
- 如何实现std ::何时_any而不进行轮询
- 如何正确安全地实现 std::array 的C++算术运算符
- 与自定义命名空间一起使用时实现 std::error_category、名称解析问题
- 如何为模板类实现std ::哈希
- 为什么标准库不以无锁的方式为 8 字节以下的结构实现 std::atomic?
- 为什么 MSVC 在实现 std::bitset::count 时不使用 __popcnt?
- 实现 std::tuple 的详细信息
- 如何实现std :: set(红色/黑色树)前迭代
- 以C 标准的方式实现STD :: Malloc
- 如何为自定义模板化迭代器实现 std::d istance()
- 如何实现 std::map::查找包含两个结构'Pos'结构的比较逻辑,每个结构包含 x 和 y 坐标
- 实现 std::vector::p ush_back 强异常安全
- 是否可以实现std ::移动和清除功能