c++ 如何在不改变 end() 的情况下擦除元素
Posted
技术标签:
【中文标题】c++ 如何在不改变 end() 的情况下擦除元素【英文标题】:c++ How to erase an element without changing its end() 【发布时间】:2019-12-25 02:08:33 【问题描述】:我正在尝试按以下索引从向量中删除一个元素,但为什么第一个输出与第二个输出不同?有什么方法可以避免这种情况,或者有更好的删除元素的方法吗?
int main()
vector<int> test = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10;
cout << *test.end() << endl;
test.erase(test.begin() + 2);
cout << *test.end() << endl;
return 0;
【问题讨论】:
end() 是最后一个元素之后的元素,解引用没有意义*test.end()
是未定义的行为。
我只是想证明 end 实际上发生了变化,因为有时我可能想比较它们
你不能通过取消引用一个不可引用的迭代器来“证明”任何事情。
“有时我可能想比较它们” 这也没有意义;如果您要在erase
之前缓存test.end()
的结果并在erase
之后使用它,那么您将再次出现未定义的行为(即使使用==
),因为迭代器将失效。你的真正问题是什么?
【参考方案1】:
std::vector::end
将迭代器返回到元素在最后一个元素之后,对它的解引用导致UB,意味着一切皆有可能,只是没有意义。
返回一个迭代器,指向容器最后一个元素之后的元素。
此元素充当占位符;尝试访问它会导致未定义的行为。
您可以使用std::vector::back
来获取最后一个元素; (最好提前检查vector
是否为空。)
int main()
vector<int> test = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10;
cout << test.back() << endl;
test.erase(test.begin() + 2);
cout << test.back() << endl;
return 0;
【讨论】:
但是我擦除元素后,end()变成了10,这是定义的,我该如何避免呢? @WhalalalalalalalaCHen end() not “变成 10”。停止取消引用它。你不能那样做。 @WhalalalalalalaCHen 只是不要取消对具有 UB 的end
的引用。你想避免什么?
我想通过 find(test.begin(), test.end(), element) == test.end() 来检查一个元素是否存在
那就这样做吧。这与您在问题中提出的内容或您在 cmets 中不断说的话有什么关系?【参考方案2】:
通常你不能打印 *test.end()
,因为它不是最后一个指针,它在最后一个指针之后。它的值对你无效,可能会导致异常。
vector::end() == vector::begin() + vector::size()
你可以使用vector::back
我检查了vector::erase()的stl代码
iterator erase(const_iterator _Where) noexcept(is_nothrow_move_assignable_v<value_type>) /* strengthened */
const pointer _Whereptr = _Where._Ptr;
auto& _My_data = _Mypair._Myval2;
pointer& _Mylast = _My_data._Mylast;
#if _ITERATOR_DEBUG_LEVEL == 2
_STL_VERIFY(
_Where._Getcont() == _STD addressof(_My_data) && _Whereptr >= _My_data._Myfirst && _Mylast > _Whereptr,
"vector erase iterator outside range");
_Orphan_range(_Whereptr, _Mylast);
#endif // _ITERATOR_DEBUG_LEVEL == 2
_Move_unchecked(_Whereptr + 1, _Mylast, _Whereptr);
_Alty_traits::destroy(_Getal(), _Unfancy(_Mylast - 1)); // here after move it destroy the last element.
--_Mylast;
return iterator(_Whereptr, _STD addressof(_My_data));
所以使用 *end() 可能会导致野指针异常。
【讨论】:
*test.end()
既不能正常也不能异常,你不需要检查代码,文档就足够了。它不是指针而是迭代器。【参考方案3】:
尝试列表
#include <vector>
#include <list>
int main()
list<int> test = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10;
auto pbeg=test.begin(),
pend=test.end(),
a = pbeg, b = pend;
cout << *(--b) << endl;
++(++a);
test.erase(a);
cout << *(--b) << endl;
for ( a=pbeg; a!=pend; ++a)
cout<< *a <<" ";
return 0;
10
10
1 2 4 5 6 7 8 9 10
【讨论】:
【参考方案4】:如果您想在从容器中擦除或移除项目期间避免迭代器失效,则需要重新访问您对容器的选择。
下面的链接可以提供迭代器失效的概述:
http://kera.name/articles/2011/06/iterator-invalidation-rules-c0x/
【讨论】:
以上是关于c++ 如何在不改变 end() 的情况下擦除元素的主要内容,如果未能解决你的问题,请参考以下文章