C++ 如何检查迭代器是否已初始化?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6954949/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 21:01:15  来源:igfitidea点击:

How to check if the iterator is initialized?

c++iterator

提问by B?ови?

If I use a default constructor for an iterator, how to check if it was assigned later on?

如果我为迭代器使用默认构造函数,如何检查它是否在稍后分配?

For pointers, I could do this :

对于指针,我可以这样做:

int *p = NULL;
/// some code
if ( NULL == p ) {
  // do stuff
}

How do I do the above for iterators? Is it possible at all?

我如何为迭代器执行上述操作?有可能吗?

#include <iostream>
#include <list>

int main ()
{
    std::list<int>::iterator it;

  if ( NULL == it ) // this fails
  {
      std::cout<<"do stuff" << std::endl;
  }
}

采纳答案by B?ови?

I managed to find this in the current standard (c++03 ). 24.1 p 5 tells :

我设法在当前标准 (c++03) 中找到了这一点。24.1 p 5 告诉:

Just as a regular pointer to an array guarantees that there is a pointer value pointing past the last element of the array, so for any iterator type there is an iterator value that points past the last element of a corresponding container. These values are called past-the-end values. Values of an iterator i for which the expression *iis defined are called dereferenceable. The library never assumes that past-the-end values are dereferenceable. Iterators can also have singular values that are not associated with any container.[Example: After the declaration of an uninitialized pointer x(as with int* x;), xmust always be assumed to have a singular value of a pointer. ] Results of most expressions are undefined for singular values; the only exception is an assignment of a non-singular value to an iterator that holds a singular value.In this case the singular value is overwritten the same way as any other value. Dereferenceable values are always non- singular.

正如指向数组的常规指针保证有一个指针值指向数组的最后一个元素,因此对于任何迭代器类型,都有一个指向相应容器的最后一个元素的迭代器值。这些值称为最终值。为其*i定义表达式的迭代器 i 的值 称为可解引用。库从不假设越过末尾的值是可取消引用的。迭代器也可以有不与任何容器关联的奇异值。[示例:在声明未初始化的指针x(如int* x;)之后, x必须始终假定指针具有奇异值。] 对于奇异值,大多数表达式的结果是未定义的;唯一的例外是将非奇异值分配给保存奇异值的迭代器。在这种情况下,奇异值的覆盖方式与任何其他值相同。可取消引用的值总是非单数的。

(Emphasis mine)

(强调我的)

So the answer is : no, it is not possible.

所以答案是:不,这是不可能的。

回答by Kerrek SB

Most iterators don't have any global special values in the same way that all pointers can be NULL. Typically, though, you'll be working with specific containers, and if you keep one iterator per container, then you can use end()as the sentinel value:

大多数迭代器没有任何全局特殊值,就像所有指针都可以为 NULL 一样。但是,通常情况下,您将使用特定的容器,并且如果您为每个容器保留一个迭代器,那么您可以将其end()用作标记值:

std::list<int> mylist;
std::list<int>::iterator it = mylist.end();

/* do stuff */

if (it == mylist.end()) { ... }

I'm not sure if insertion/deletion invalidates the end()iterator, though, so if you're planning on modifying your container, maybe save a copy of the original end, too:

不过,我不确定插入/删除是否会使end()迭代器失效,因此,如果您打算修改容器,也可以保存原始结尾的副本:

std::list<int>::iterator end = mylist.end(), it = end;

if (it == end) { ... }

Though again I'm actually not sure if it's well-defined to compare two invalid iterators (in the event that the two do get invalidated).

虽然我实际上不确定比较两个无效迭代器是否定义良好(如果两个迭代器无效)。

回答by code7amza

Since there is no default value for iterators (like there is NULL for pointers), in situation where i need a common default value for a Object::iterator(before any actual Object has been created) I create a dummy static variable and use its ::end()as the default.

由于迭代器没有默认值(就像指针有 NULL 一样),在我需要 a 的通用默认值Object::iterator(在创建任何实际对象之前)的情况下,我创建了一个虚拟静态变量并将其::end()用作默认值。

Update : This only works for Release, because in DEBUG (or with _HAS_ITERATOR_DEBUGGING=1) comparison operators check if both iterators point to the same object/container.

更新:这仅适用于 Release,因为在 DEBUG(或 with _HAS_ITERATOR_DEBUGGING=1)比较运算符中检查两个迭代器是否指向同一个对象/容器。

For example for vector<int>I would do :

例如,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";
}

回答by Jiri Kriz

This question has already been treated in Stackoverflow. The quintessence is that the default constructor initializes an iterator to a singular value, and the only addmissible operation on it is to assign it another iterator value. In particular it is not possible to query the value of such unitialized iterator. Therefore it is a good programming practice to initialize the iterator to a specific value of a specific container, which then can be tested for.

这个问题已经在Stackoverflow 中处理过了。精髓是默认构造函数将迭代器初始化为奇异值,唯一可对其进行的操作是为其分配另一个迭代器值。尤其是不可能查询这种单元化迭代器的值。因此,将迭代器初始化为特定容器的特定值是一个很好的编程实践,然后可以对其进行测试。

回答by cprogrammer

You can't. ll you can do is compare against list end

你不能。你能做的就是与列表末尾进行比较

it != mylist.end();

回答by Nawaz

In C++, uninitialized local variables can have anyvalue i.e it contains simply garbage. That implies, you cannotcheck it against some well-defined value, to determine if the variable is uninitialized or not.

在 C++ 中,未初始化的局部变量可以有任何值,即它包含简单的垃圾。这意味着,您不能根据某个定义良好的值检查它,以确定变量是否未初始化。

Not only that if the variable is not initialized and you write this:

不仅如此,如果变量未初始化并且您这样写:

if ( NULL == it ) // this fails

then it invokes undefined behavior.

然后它调用未定义的行为。

回答by vsz

Maybe you should always assign a predefined value, like NULL, after creating the iterator. Later you can easily check against NULL. This will make your code more portable, as you will not depend on what starting values the uninitialized variables take at the beginning.

也许你应该在创建迭代器后总是分配一个预定义的值,比如 NULL。稍后您可以轻松检查 NULL。这将使您的代码更具可移植性,因为您将不依赖于未初始化变量在开始时采用的起始值。

回答by leftaroundabout

The best way to do this I can think of is something like

我能想到的最好的方法是

#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;
}

but it's not exactly a safe solution (because it relies on the non-const global containers in nullcontainers).

但这并不是一个完全安全的解决方案(因为它依赖于 中的非常量全局容器nullcontainers)。

回答by Pedro Ferreira

As far as I know you must always initialize your iterators and the easiest way is to make them equal to 'container'.end() In certain cases it looks like working, we had some problems with code that worked with VC6 and stopped working with VC2010. Look at this example compiled with g++ where it works for the vector but not for the map:

据我所知,您必须始终初始化您的迭代器,最简单的方法是使它们等于 '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;
}

回答by Thomas Horn

I used the following solution:

我使用了以下解决方案:

const MyList_t::const_iterator NullIterator(NULL);
const_iterator MyList_t::MyIterator;

Then a check is possible:

然后可以进行检查:

if (NullIterator != MyIterator) {}