2010-06-12 260 views
2

我的工作,我画了几个图像,像这样的aplication:如何在C++中使用迭代器时获得循环次数?

void TimeSlice::draw(float fX, float fY) { 
list<TimeSliceLevel*>::iterator it = levels.begin(); 
float level_x = x; 
float level_y = y; 
while(it != levels.end()) { 
    (*it)->draw(level_x,level_y); 
    level_y += (*it)->height; 
    ++it; 
} 

}

虽然这是一个有点不正确。我需要将TimeSliceLevel *放在X上..当我 得到for(int i = 0; i < slices.size(); ++i)循环时,我可以使用x = i * width。尽管我使用迭代器,正如我多次被告知的那样,这是很好的编程:>并且我想知道迭代器是否具有可用于计算新X位置的“索引”数量? (因此,它更是一个有关使用迭代器的问题)

亲切的问候, 北河三

+1

对于除std :: vector或数组以外的所有情况,这是非常低效的。在任何情况下,索引可以像下面这样计算:std :: size_t index = std :: distance(levels.begin(),it); – Hippicoder 2010-06-13 07:44:07

回答

3

不,不。如果您需要整数索引,请使用for循环。尽管一些迭代极端主义者会相信,for循环仍然在C++代码中占有一席之地。

+3

在一个链接上这不会使它成为O(N^2)吗? – 2010-06-12 18:41:39

+2

@Paul我几乎从不使用列表,我没有注意到OP正在这样做。如果他真的需要一个列表,那么迭代器就是答案,但我的经验是,大多数人选择列表没有任何理由,几乎总是通过使用vector或deque来更好地服务列表。 – 2010-06-12 18:47:18

+0

他想要一个整数索引(用于X偏移量)和一个迭代器(用于列表访问)。我不打扰,但仍然使用for循环:'for(iterator i = collection.begin(); i!= collection.end(); ++ i,x + = width){/ * draw(x,y )* /}' – MSalters 2010-06-14 12:15:39

7

它们没有,因为迭代器除了从有序的索引列表的开始到结束循环以外,还可以用于其他目的。你需要单独跟踪的指数,并增加它的每一通:

list<TimeSliceLevel*>::iterator it; 
int index; 

for(it = levels.begin(), index = 0; it != levels.end(); ++it, ++index) { 
    ... 
} 
0

你将不得不写类似

size_t index = 0; 
for (list<...>::const_iterator it = y.begin(); it != y.end(); ++it) { 
    // Do your actions based on `index` 
    ++index; 
} 

的,那么,这是有时适合

在另一方面,你可以重构(重新计划)您的应用程序,使您的实际绘图循环没有使所有这些x += something, y += something2, ...,而是作用于以下方式:

foreach (Level* level, list) { 
    level->draw(backend); 
} 

它有时可能会很棘手,但在我看来,如果您的应用程序增长到“大”,这种方法可以为您节省大量时间。

+0

谢谢科蒂,我会如何计算位置呢?什么是后端? – pollux 2010-06-12 18:34:03

+0

@pollux这是一个棘手的问题,它与您的问题域相关联。我的主要想法是,你可以将你的'x'和'y'存储在你的关卡中(或其他),或者让它们从一些基本的'Object'超类派生。 *不幸的是,我无法给你提供很多建议,因为我对你的应用程序的工作方式一无所知。 – 2010-06-12 18:55:55

+0

@pollux'Backend'这里是一些抽象渲染引擎/界面。例如,你可以有* WinAPI后端,DirectX后端,OpenGL后端*,你应该把它传递给对象的绘制方法,所以你的对象会知道**“绘制的地方”。** – 2010-06-12 18:57:20

0

您可以但只能用于随机访问迭代器。如果它是一个随机访问迭代器,则可以从开始迭代器中减去迭代器以获取索引(而不保留单独的int索引变量)。

for (vector<int>::const_iterator cit = v.begin(); cit != v.end(); ++cit) 
{ 
    cout << "This is element no: " << cit - v.begin() << endl; 
} 

在您的例子不幸的是你将不能够做到这一点,因为你使用的std ::名单,这仅仅是一个双向迭代。使用std :: vector,你可以像我的例子那样做。

+0

顺便说一句,我不得不提到我这并不是真的提倡这种方式。如果您确实需要索引,我不会看到任何与索引变量循环有关的错误。 我只是指出确实有办法。 – ryaner 2010-06-12 18:43:40

1

对于一些迭代器类型,只需减去初始迭代器当前迭代:

index = it - levels.begin()

由于本作的std ::列表迭代器不工作,只是一个变量跟踪指标明确,如在上面的答案中提到。使用迭代器和容器的好处不会丢失。您正在添加容器不提供的要求。

2

从iterator - > index是可能的。至少有两种方式:

  1. 使用-随机访问迭代器(即i - container.begin()
  2. 使用std::distance(即std::distance(containter.begin(), i))。这是一个更“通用”的解决方案,并会在随机访问迭代器的情况下,以-得益于专业化相同的执行,反而会产生可怕的影响性能,否则

不过,我不会建议他们要么,因为它混淆代码(并且可能是不正常的)。与其他人所说的一样,请使用额外的计数器。在需要时使用索引没有什么“错误”,宁愿使用迭代器是为了帮助编写“通用”代码,因为您可以将算法应用于不同的容器或容器的子集,等等。

+0

+1为std :: distance,也指出这通常是不必要的。在OP的情况下,只要每次迭代增加一个索引就没有问题。 – stinky472 2010-06-28 20:44:25