通过在 C++ 中单独直接访问容器的迭代器来删除容器的元素
Deleting an element of a container by directly accessing its iterator alone in C++
我已经在我的主函数中声明了一个std::vector<int>
,并希望从中删除所有偶数元素,但只能将其迭代器传递给名为 remove_even
的函数,该函数接受容器的开始和结束迭代器。
#include <iostream>
#include <algorithm>
#include <vector>
void remove_even(auto start, auto end) {
while(start != end) {
if(*start % 2 == 0)
// Remove element from container
}
}
int main() {
std::vector<int> vec = {2, 4, 5, 6, 7};
remove_even(vec.begin(), vec.end());
}
有没有办法在C++中做到这一点,或者我必须直接将我的向量传递给函数?
类std::vector
本身具有允许擦除向量中所需元素的方法erase
。
使用迭代器所能做的只是调用标准算法std::remove_if
然后在调用方法 erase
时使用返回的迭代器。
例如
#include <iostream>
#include <vector>
#include <algorithm>
std::vector<int>::iterator remove_even( std::vector<int>::iterator first,
std::vector<int>::iterator last )
{
return std::remove_if( first, last, []( int x ) { return x % 2 == 0; } );
}
int main()
{
std::vector<int> vec = { 2, 4, 5, 6, 7 };
for ( int x : vec ) std::cout << x << ' ';
std::cout << std::endl;
vec.erase( remove_even( vec.begin(), vec.end() ), vec.end() );
for ( int x : vec ) std::cout << x << ' ';
std::cout << std::endl;
}
程序输出为
2 4 5 6 7
5 7
这是IMO的正确方式:
template <typename T>
T remove_even(T start, T end) {
return std::remove_if(start,end,[](const auto& item){return item%2==0;};
}
int main() {
std::vector<int> vec = {2, 4, 5, 6, 7};
vec.erase(remove_even(vec.begin(), vec.end()),vec.end());
}
从 cplusplus.com:
迭代器是指向元素范围(如数组或容器)中的某个元素的任何对象,它能够使用一组运算符(至少具有增量 (++) 和取消引用 (*) 运算符)遍历该范围的元素。
如引文中所述,它指向一系列元素中的一个元素。它不需要提供有关其所在范围的任何信息,即有关存储元素的容器的信息。
如注释中所述,从向量(或任何其他容器)中删除元素是影响容器的操作,而不仅仅是对象。因此,您将始终必须在容器上调用erase()
或类似函数。
您询问的内容(有点,不完全)与此类似:
void remove_or_not(int& i){
//do something with i to remove it from a container
//but we dont have a container here
}
int main(){
std::vector<int> vec;
//fill vec and generate some int n
remove_or_not(vec[n]);
}
在上面的例子中调用remove_or_not()
时,我们只是传递对 int 的引用 - 我们完全丢失了它在容器内的信息,所以很明显我们不能从任何容器中删除它。
当尝试使用迭代器进行相同的操作时,我们仍然拥有元素在容器内的信息 - 但我们可能已经丢失了哪个容器中的信息,因为迭代器不需要保留此信息。
例如,C 样式数组上的迭代器可以只是一个指针。我们可以递增和递减它,并将其与指向第一个元素的指针和最后一个元素后面的指针进行比较。但是根本不需要知道数组的大小或数组的任何信息。
PS:有关如何正确实现所需内容的方法,请参阅已经发布的答案,我认为没有必要重复这些。
办法通过仅将迭代器传递给函数来做到这一点。您必须将整个向量传递给函数,如下所示:
void remove_even(std::vector<int> v)
{
for (auto it = v.begin(); it != v.end();) {
if ((*it) % 2 == 0) {
it = v.erase(it);
} else {
++it;
}
}
}
您可能需要考虑通过 x 值引用传递容器然后返回复制/移动版本的习惯用法。
这提供了效率以及呼叫站点的可读性的优势。
下面是一个扩展示例。
请注意,编译器 (RVO) 将省略(优化)向量的所有"明显"复制。
另请注意,由于Container&&
是在推导的上下文中评估的,因此它将自动成为const Container&
或Container&&
,以调用站点上下文中最合适的为准。这意味着相同的功能既可以用来改变现有的容器(x = sorted(x)
),也可以用于制作一个变异的副本(x = sorted(y)
#include <iostream>
#include <vector>
#include <algorithm>
template<class Container, class Predicate>
auto all_except(Container&& c, Predicate&& pred)
{
auto result = std::forward<Container>(c);
result.erase(std::remove_if(std::begin(result),
std::end(result),
std::forward<Predicate>(pred)),
std::end(result));
return result;
}
template<class Container>
auto sorted(Container&& c)
{
auto result = std::forward<Container>(c);
std::sort(std::begin(result), std::end(result));
return result;
}
auto even_items = [](auto const& item) { return item % 2 == 0; };
auto odd_items = [](auto const& item) { return item % 2 != 0; };
template<class Vec>
void emit(const Vec& v)
{
std::cout << "[";
auto sep = " ";
for (auto const& e : v) {
std::cout << sep << e;
sep = ", ";
}
std::cout << " ]" << std::endl;
}
int main()
{
std::vector<int> vec = {65, 2, 32, 63, 9, 13, 88, 22, 4, 5, 6, 7};
emit(all_except(vec, even_items));
emit(all_except(vec, odd_items));
emit(all_except(sorted(vec), odd_items));
vec = sorted(all_except(std::move(vec), even_items));
emit(vec);
return 0;
}
预期成果:
[ 65, 63, 9, 13, 5, 7 ]
[ 2, 32, 88, 22, 4, 6 ]
[ 2, 4, 6, 22, 32, 88 ]
[ 5, 7, 9, 13, 63, 65 ]
- 对于set上的循环-获取next元素迭代器
- 访问要输出的矢量迭代器元素
- 为什么这个程序没有打印返回的迭代器的正确第二个元素?
- C++如何乘以包含 std::variant 元素的向量的迭代器?正在执行迭代器类型的转换?
- 调用 erase() 函数是否也会在擦除元素之前更改迭代器值?
- 为什么 min_element() 返回最小元素的索引,而不是迭代器?
- 如何通过查找迭代器结果分配给一组对的元素
- C++:在进行切片时对迭代器的约定,特别是对于访问最后一个元素并最终将其删除
- 将迭代器作为 3 个元素的滑动窗口,可以超调边界(可能使用 Boost)
- C++链表最后一个元素的迭代器?
- 使用索引与迭代器将向量迭代到倒数第二个元素
- 提升堆元素句柄比较和 MSVC 迭代器调试工具
- 如果我有一个指向矢量元素的指针,而不是迭代器,如何删除它?
- 使用迭代器打印矢量元素
- C++ std::vector语言 - 如何修改迭代器指定的元素?
- 你能pop_back一个向量,并且仍然使用迭代器到最后一个元素吗?
- 优先级队列(使用 pairs<int,int> ) 根据 for 循环迭代器的顶级元素
- C++ 当容器在使用前被破坏/修改时发出警告(通过引用元素或迭代器使用)
- 如何从该列表的元素中获取 std::list<T>::迭代器?
- 如何在c++中记忆迭代器元素