顺序容器|| C ++ Primer第五版练习9.22

时间:2014-09-29 10:55:55

标签: c++ iterator containers sequential

我对这项练习感到困惑。

  

练习9.22:假设iv是一个int的向量,下面的程序出了什么问题?你怎么能纠正这个问题?

vector<int>::iterator iter = iv.begin(),
                      mid  = iv.begin() + iv.size()/2;

while(iter != mid)     
    if(*iter == some_val)
        iv.insert(iter, 2 * some_val)

我要做的第一件事就是去询问这个程序的意图是什么。因为我不确定是谁写了这本书的这一部分,并且不想打扰作者的一些可能微不足道的事情我开始猜测。

我假设他们想要在向量中插入第一个值的double,直到值在中间。 (因为他们将它指向开头并且永远不会通过向量来寻找实际值(然后他们再次命名为some_val,寻找不在开头的值是一个微不足道的修复,但是那时必须验证该值实际上是在容器的前半部分))

所以a)矢量会像这样增长吗?

{1,2,3,4,5}
{(2),1,2,3,4,5}
{2,(2),1,2,3,4,5}
{2,2,(2),1,2,3,4,5}

在这种情况下的第一个问题是,插入向量很可能立即使迭代器无效。 我们可以使用列表,但是我们不能使用迭代器算法来计算mid。 像在示例中一样只计算一次中间是不够的,因为在像。)这样的列表中它会指向3并继续指向3,只是因为我们调用了迭代器mid并用中间元素初始化了他并不意味着它仍然指向所有插入后的中间位置。

所以这就是我所做的:

vector<int>::iterator iter=iv.begin();

while(iter!=iv.begin()+iv.size()/2){    //calculating mid each time
    if(*iter==some_val)
        iv.insert(iter,2*some_val);

    iter=iv.begin();                        //revalidate iter
    while(*iter!=some_val)                  //find the original first element
        ++iter;
}

我看到这个练习如何强迫你考虑使用哪个顺序容器以及迭代器在一个不断增长的容器中的行为,但是练习的方式仍然令我感到困惑。我错过了一些明显的观点吗?

PS:由于整章都涉及顺序容器,所以我没有关注while循环中的条件所带来的问题(就像他们忘记了几章前他们教过的所有内容)。

2 个答案:

答案 0 :(得分:1)

让我们一步一步地完成程序,并将代码样式更新为现代C ++:

auto iter = iv.begin(); // type will be std::vector<int>::iterator
const auto mid  = iv.begin() + iv.size()/2; // type will be std::vector<int>::iterator

while(iter != mid)
{
  if(*iter == some_val)
    iv.insert(iter, 2 * some_val);
}

前两行创建迭代器对。 循环迭代,直到到达向量的中间。 循环内的条件检查位置iter指向的值是否等于某个预定义值someval。 下一行代码在向量中插入一个新项,等于some_val的值的两倍。

现在回答你的问题:插入行确实使所有迭代器无效,这确实是程序中的问题。此外,迭代器不会迭代,因为它永远不会递增。 通过使用insert调用的返回值使iter有效且可以再次使用,可以解决一个失效问题:

iter = iv.insert(iter, 2*some_val);

但这仍然留给我们mid。您的问题中没有足够的信息来修复此位,但可能的选项是:

while(std::distance(iter, iv.end()) > iv.size()) // shift the middle when the vector grows

const auto half = iv.size()/2;
while(std::distance(iter, iv.begin()) < half) // only iterate until iter is halfway the original length by insertion

所以示例解决方案可能如下所示:

auto iter = iv.begin();

while(std::distance(iter, iv.begin()) < iv.size()/2) // iterate until halfway the current vector
{
  if(*iter == some_val)
    iter = iv.insert(iter, 2 * some_val);
  else
    ++iter;
}

但这当然不是预期的解决方案。

答案 1 :(得分:0)

原始代码不会使所有使用过的迭代器前进并使其无效。

 vector<int>::iterator iter = iv.begin(),
                          mid  = iv.begin() + iv.size()/2;

 while(iter != mid)
         if(*iter == some_val)
                  iv.instert(iter, 2 * some_val);

还有更多问题

vector<int>::iterator iter = iv.begin(),
                      mid  = iv.begin() + iv.size()/2;
int s = iv.size()/2; // assuming we should stop at the original position

while(iter != iv.begin() + s) { // update end condition if that is the intended function
     if(*iter == some_val) {
              iter = iv.instert(iter, 2 * some_val); // gets new valid iter
              ++s; // update position of mid 
              ++iter; // skips the inserted
     }
     ++iter; // advance in vector.
}