如果我为迭代器使用默认构造函数,如何检查它是否稍后被分配?
对于指针,我可以这样做:
int *p = NULL;
/// some code
if ( NULL == p ) {
// do stuff
}
如何为迭代器执行上述操作? 它有可能吗?
#include <iostream>
#include <list>
int main ()
{
std::list<int>::iterator it;
if ( NULL == it ) // this fails
{
std::cout<<"do stuff" << std::endl;
}
}
答案 0 :(得分:17)
我设法在当前标准(c ++ 03)中找到了这个。 24.1 p 5告诉:
就像指向数组的常规指针一样,确保存在 指针值指向数组的最后一个元素,因此对于任何 迭代器类型有一个指向过去的迭代器值 相应容器的元素。调用这些值 过去的价值观。迭代器的值i为其表达式 我定义的被称为可解除引用。图书馆永远不会假设 过去的价值是可以解除引用的。 迭代器也可以 与任何容器无关的奇异值。 [示例: 在声明未初始化的指针x之后(与int x;一样), 必须始终假定x具有指针的奇异值。 ] 大多数表达式的结果未定义为奇异值;该 唯一的异常是将非奇异值赋给迭代器 具有奇异值。在这种情况下,奇异值是 以与任何其他值相同的方式覆盖。可解除引用的值 总是非单数的。
(强调我的)
所以答案是:不,这是不可能的。
答案 1 :(得分:3)
大多数迭代器没有任何全局特殊值,就像所有指针都可以为NULL一样。但是,通常情况下,您将使用特定容器,如果每个容器保留一个迭代器,则可以使用end()
作为标记值:
std::list<int> mylist;
std::list<int>::iterator it = mylist.end();
/* do stuff */
if (it == mylist.end()) { ... }
我不确定插入/删除是否会使end()
迭代器失效,所以如果您计划修改容器,也可以保存原始结尾的副本:
std::list<int>::iterator end = mylist.end(), it = end;
if (it == end) { ... }
虽然我实际上不确定它是否被定义为比较两个无效的迭代器(如果这两个迭代器失效)。
答案 2 :(得分:1)
在C ++中,未初始化的局部变量可以具有任何值,即它只包含垃圾。这意味着,无法根据一些明确定义的值进行检查,以确定该变量是否未初始化。
不仅如果变量未初始化并且你写了这个:
if ( NULL == it ) // this fails
然后它调用未定义的行为。
答案 3 :(得分:1)
此问题已在Stackoverflow中得到处理。精髓是默认构造函数将迭代器初始化为奇异值,并且唯一可添加的操作是为其分配另一个迭代器值。特别是不可能查询这种单元化迭代器的值。因此,将迭代器初始化为特定容器的特定值是一种很好的编程习惯,然后可以对其进行测试。
答案 4 :(得分:1)
由于迭代器没有默认值(就像指针有NULL),在我需要Object::iterator
的公共默认值的情况下(在创建任何实际的Object之前),我创建了一个虚拟静态变量并使用其::end()
作为默认值。
更新:这仅适用于Release,因为在DEBUG中(或使用_HAS_ITERATOR_DEBUGGING=1
)比较运算符检查两个迭代器是否指向同一个对象/容器。
例如对vector<int>
我会这样做:
class A
{
public :
A() : myIterator1(dummyVector.end()), myIterator2(dummyVector.end()) {}
// needed iterators
vector<int>::iterator myIterator1;
vector<int>::iterator myIterator2;
static const vector<int> dummyVector;
}
#define IT_NULL A::dummyObject.end()
void maint() {
A::dummyObject = vector<int>(); // initialize the Null iterator
A a;
if(a.myIterator1 == IT_NULL) cout << "Iterator not yet initialized";
}
答案 5 :(得分:0)
你做不到。你能做的就是与列表结尾进行比较
it != mylist.end();
答案 6 :(得分:0)
在创建迭代器之后,也许你应该总是分配一个预定义的值,比如NULL。稍后您可以轻松检查NULL。 这将使您的代码更具可移植性,因为您不会依赖于未初始化变量在开始时采用的起始值。
答案 7 :(得分:0)
if(std::list<int>::iterator() == it)
但我怀疑......有可能,有效的迭代器可以通过比较。 最好避免这些情况。如果不可能通过指针存储迭代器。
std::auto_ptr<std::list<int>::iterator> it;
答案 8 :(得分:0)
我能想到的最好的方法是
#include <utility>
#include <map>
#include <typeinfo>
#include <string>
namespace nulliterators {
typedef std::map<std::string, void*> nullcntT;
nullcntT nullcontainers;
template<class containerT>
typename containerT::iterator iterator() {
containerT* newcnt = new containerT();
std::string cnttypename = typeid(*newcnt).name();
nullcntT::iterator i = nullcontainers.find(cnttypename);
if (i==nullcontainers.end()) {
nullcontainers.insert(make_pair(cnttypename, newcnt));
return newcnt->end();
}else{
delete newcnt;
return (static_cast<containerT*>(i->second))->end();
}
}
}
template<class containerT>
typename containerT::iterator nulliterator() { return nulliterators::iterator<containerT>(); }
#include <list>
#include <iostream>
int main(){
std::list<int>::iterator nullinitized = nulliterator< std::list<int> >();
std::list<int> somelist;
std::list<int>::iterator initialized = somelist.end();
if (nullinitized == nulliterator< std::list<int> >())
std::cout << "nullinitized == nulliterator< std::list<int> >()\n"; //true
else
std::cout << "nullinitized != nulliterator< std::list<int> >()\n";
if (initialized == nulliterator< std::list<int> >())
std::cout << "initialized == nulliterator< std::list<int> >()\n";
else
std::cout << "initialized != nulliterator< std::list<int> >()\n"; //true
return 0;
}
但它并不是一个安全的解决方案(因为它依赖于nullcontainers
中的非const全局容器)。
答案 9 :(得分:0)
据我所知,你必须始终初始化你的迭代器,最简单的方法是使它们等于'container'.end() 在某些情况下,它看起来像工作,我们遇到了一些问题,代码与VC6一起工作,并停止使用VC2010。看看这个用g ++编译的例子,它适用于矢量,但不适用于地图:
# Test iterator init, compile with: g++ test-iterator.cpp -o test-iterator
#include <iostream>
#include <vector>
#include <map>
int main()
{
std::vector<int> vec;
std::vector<int>::iterator it;
if (it != vec.end())
{
std::cout << "vector inside!" << std::endl;
}
else
{
std::cout << "vector outside!" << std::endl;
}
std::map<int, int> mp;
std::map<int, int>::iterator itMap;
if (itMap != mp.end())
{
std::cout << "map inside!" << std::endl;
}
else
{
std::cout << "map outside!" << std::endl;
}
return 0;
}
答案 10 :(得分:0)
我使用了以下解决方案:
const MyList_t::const_iterator NullIterator(NULL);
const_iterator MyList_t::MyIterator;
然后可以检查:
if (NullIterator != MyIterator) {}