在学习删除-惯用语的同时,并了解std :: min_element()如何工作How to use std::min_element in C++17?。我想尝试从以下代码中删除最少的元素:
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v{3, 1, 4, 1, 5, 9};
std::vector<int>::iterator result = std::min_element(v.begin(), v.end());
std::cout << "min element at: " << std::distance(v.begin(), result);
}
v中有两个最低限度的元素。我试图通过添加诊断程序将它们都删除
int main()
{
std::vector<int> v{3, 1, 4, 1, 5, 9};
std::vector<int>::iterator result = std::min_element(v.begin(), v.end());
v.erase(result); // This removes just one minimum. What if need to remove all?
v.push_back(1); // Okay, let's add the minimum again
std::vector<int>::iterator another_result = std::min_element(v.begin(), v.end());
std::cout << "min element: " << *another_result << std::endl;
auto iter = std::remove(std::begin(v), std::end(v), *another_result);
// If I write 1 instead of *another_result, I manage to remove all 1's. No need to use iter-1 in erase idiom then.
std::cout << "\nWhere is my iterator pointing? It is at: " << std::distance(v.begin(), iter);
v.erase(iter, std::end(v)); // All the minimum are gone if I use iter-1 instead of iter and use *another_result
std::for_each(v.begin(), v.end(), [](const int& x){std::cout << x << " ";}); // Why is still "1" there?
}
我的问题是带有注释的代码中突出显示的
auto iter = std::remove(std::begin(v), std::end(v), 1);
但是
auto iter = std::remove(std::begin(v), std::end(v), *another_result);
在坚持删除擦除习惯用法时,不会删除所有minimum实例。
答案 0 :(得分:7)
您似乎正在将参考与向量进行比较。然后,您传入的元素将移动remove
,并在与之进行第二次比较时,引用将观察到其他值。
这很好用:
int by_value = *another_result;
auto iter = std::remove(std::begin(v), std::end(v), by_value);
您正在使用的std::remove
重载的第三个参数采用const T&
,但它在执行操作的过程中“使引用无效”。
如果您查看en.cppreference上的“可能的实现”
template< class ForwardIt, class T >
ForwardIt remove(ForwardIt first, ForwardIt last, const T& value)
{
first = std::find(first, last, value);
if (first != last)
for(ForwardIt i = first; ++i != last; )
if (!(*i == value))
*first++ = std::move(*i); //here it changes the value that "value" points to
//if you are using a reference of an element inside the vector
return first;
}
此问题在“注释”部分中也提到为:
由于std :: remove通过引用获取值,因此可能会出现意外情况 行为,如果它是对[first, 最后)。
答案 1 :(得分:1)
如果您要一次性删除所有最小值,可以执行以下操作:
template<class T>
void remove_min( std::vector<T> &container ) {
if ( container.empty() ) return;
T min_val = *std::min_element( container.begin(), container.end() );
container.erase( std::remove( container.begin(), container.end(), min_val ), container.end() );
}
请注意,min_val
首先是副本(请参阅PeterT的答案以获取解释)。上面的内容可能可以修改为与其他容器一起使用。
请记住,std::remove
并没有真正删除任何内容。该函数的返回值将指向新的 last元素所在的位置之后,然后从此处调用容器的erase
方法以删除该位置上的所有元素。