C++ 为什么';tc++;字符串迭代器检查错误?
我是一名大学生。我的任务是写单链表。我开始用nodes exposed()实现它,但使用时会导致许多空检查。然后我将节点设为私有,列表元素通过迭代器()公开,因此没有空检查,但仍然需要检查迭代器是否不在列表的末尾。我想写一个很好的实现,所以我做了一个简单的测试来检查C++ STL如何处理一些错误:C++ 为什么';tc++;字符串迭代器检查错误?,c++,error-handling,stl,iterator,C++,Error Handling,Stl,Iterator,我是一名大学生。我的任务是写单链表。我开始用nodes exposed()实现它,但使用时会导致许多空检查。然后我将节点设为私有,列表元素通过迭代器()公开,因此没有空检查,但仍然需要检查迭代器是否不在列表的末尾。我想写一个很好的实现,所以我做了一个简单的测试来检查C++ STL如何处理一些错误: #include <iostream> using namespace std; int main() { string first = "afasdasds"; string
#include <iostream>
using namespace std;
int main()
{
string first = "afasdasds";
string second = "asdadas";
int i = 0;
for(auto it = first.begin(); i < 100; it++)
{
bool result = it > second.begin();
cout << result;
i++;
}
}
#包括
使用名称空间std;
int main()
{
string first=“afasdasds”;
字符串second=“asdadas”;
int i=0;
for(auto it=first.begin();i<100;it++)
{
bool result=it>second.begin();
这是一种权衡,性能与安全
检查会减慢速度。对于迭代器来说,由于它们在紧循环中递增和取消引用,因此可能相当于一个批
STL
的许多实现通过使用库的调试版本和发布版本来缓解这一问题,因此您可以在测试期间使用检查运行,但在发布时不使用检查
不管STL
的基本原理是什么,它都鼓励更安全的编程。如果你想一想,迭代器应该总是来自一个安全的地方
也就是说,在流程开始时,您可以通过调用容器的begin()
或end()
函数获取迭代器,或者作为算法返回的结果,例如std::find
此外,还可以使用更安全的构造,例如
这种编程风格有助于保持边界安全。
当您使用索引或迭代器偏移量时,真正危险的事情就会发生,如果可能的话,应该避免这种情况。此外,存储迭代器供以后使用也不是很安全
所以一定要使用迭代器,不要使用索引(除非必须)。尽量避免让迭代器无法立即使用
但是,最重要的是,使用DEBUG
版本和test,test,test,这样您的边界检查就可以非常可靠地完成
迭代器不应该检查比较是否有意义吗
++操作符不应该检查它是否已溢出吗
因此,如果我正确地编写代码——我的意思是静态地、可证明地正确,这样在逻辑上就不会出错——我还需要为您添加的所有代码支付运行时成本来检测错误吗
您的代码应该是正确的。如果您的实现执行了这些检查,并且它们检测到错误,这意味着您的代码首先是错误的。拥有帮助您检测和修复错误的工具非常有用,但它们应该是调试辅助工具,而不是拐杖
…显然,比较不同列表中的迭代器会产生错误
比较不同列表中的迭代器会产生一个错误:在代码审查期间
此外,如果避免支付这些检查的运行时成本的唯一方法是避免使用标准库,那么许多人实际上将不得不避免使用标准库,而拥有一个人们实际上并不使用的标准库的好处有限。如果您的目标是调试和测试,那么对于gcc,您可以使用我们可以作为GNU扩展提供
第一个示例可以使用\uu gnu\u debug::string
而不是std::string
重写:
#include <iostream>
#include <debug/string>
using namespace std;
int main()
{
__gnu_debug::string first = "afasdasds";
__gnu_debug::string second = "asdadas";
int i = 0;
for(auto it = first.begin(); i < 100; it++)
{
bool result = it > second.begin();
cout << result;
i++;
}
}
#包括
#包括
使用名称空间std;
int main()
{
__gnu_debug::string first=“afasdasds”;
__gnu_调试::string second=“asdadas”;
int i=0;
for(auto it=first.begin();i<100;it++)
{
bool result=it>second.begin();
CUT不,不应该——C++的设计哲学的一部分是你不为你不明确要求的东西付费。所以检查一个迭代器是否仍然在范围内是程序员的任务,没有这样的要求。程序员不应该越界。使用迭代器的<代码> > <代码>的正确方法是<代码> f。或者(auto-it=first.begin();it!=first.end();++it)
-在我看来很简单,应该是for(const-auto&c:first)
@UnholySheep,甚至for(auto&char:first) >然后是在引擎盖下完成的:“可以说,使用迭代器的调试版本和测试、测试、测试,使用的是C++的更多范例。在这种情况下:基于循环的范围。”我想我的答案也涵盖了这一点,但我可以在这上面加一些。涉及到这个问题。它只是说明了不应该做什么。巧合的是,基于范围的for循环甚至不允许你做大部分(所有?)这些事情。但是你从来没有明确地命名过这个构造。test test*text*
?需要更多的测试;@UKMonkey Thnx(我应该假装我这样做是为了说明这一点……)这个调试输出特别有用,因为它还显示了OP甚至没有询问的东西,即完全不相关的“容器”的迭代器之间的无效比较。
#include <iostream>
#include <debug/string>
using namespace std;
int main()
{
__gnu_debug::string first = "afasdasds";
__gnu_debug::string second = "asdadas";
int i = 0;
for(auto it = first.begin(); i < 100; it++)
{
bool result = it > second.begin();
cout << result;
i++;
}
}
$ ./a.out
/usr/include/c++/7/debug/safe_iterator.h:658:
Error: attempt to order iterators from different sequences.
Objects involved in the operation:
iterator "lhs" @ 0x0x7ffd4285a5e0 {
type = __gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_debug::basic_string<char, std::char_traits<char>, std::allocator<char> > > (mutable iterator);
state = dereferenceable (start-of-sequence);
references sequence with type '__gnu_debug::basic_string<char, std::char_traits<char>, std::allocator<char> >' @ 0x0x7ffd4285a650
}
iterator "rhs" @ 0x0x7ffd4285a690 {
type = __gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_debug::basic_string<char, std::char_traits<char>, std::allocator<char> > > (mutable iterator);
state = dereferenceable (start-of-sequence);
references sequence with type '__gnu_debug::basic_string<char, std::char_traits<char>, std::allocator<char> >' @ 0x0x7ffd4285a610
}
Aborted (core dumped)