-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Exercise 9.22 #133
Comments
这个问题会在 9.3.6. Container Operations May Invalidate Iterators 里详细讲解。 那里就会有一个使用 insert 也不会让迭代器失效的例子: std::vector<int> vi = {0,1,2,3,4,5,6,7,8,9};
auto iter = vi.begin();
while (iter != vi.end()) {
if (*iter % 2) {
iter = vi.insert(iter, *iter); // duplicate the current element
iter += 2; // advance past this element and the one inserted before it
} else
iter = vi.erase(iter);
} |
Agree @pezy The specific rule goes like this:
from SO |
Code for ex9.22 : 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); In this code, we have have no way to see what |
这个很好验证。我就针对这句话举例子吧: std::vector<int> iv = {0,1,2,3,4,5,6,7,8,9};
std::vector<int>::iterator iter = iv.begin(), mid = iv.begin() + iv.size()/2; // refer to 5
iv.insert(iter, -1);
std::cout << *mid << std::endl; // print 5.
|
@pezy I think @lafener is right, I didn't notice #include <iostream>
#include <vector>
int main()
{
std::vector<int> iv = {0,1,2,3,4,5,6,7,8,9};
auto iter = iv.begin(), mid = iv.begin() + iv.size()/2;
for(int count = 50; count; --count )
{
iv.insert(iter, -1);
std::cout << "capacity = " << iv.capacity() << " *mid = " << *mid << std::endl;
}
return 0;
} output on Ubuntu 14.04 LTS ,using GCC 4.8.2:
|
The key point is reallocation. The runtime should be something like this: The code above is supposed to print 50 times. But as shown above it only printed 10 times and crashed. That's when |
@lafener 的确是对的。 比较新的标准里(草稿 N3690),对此是如此规定的:
这里要注意的是,before the insertion point. 所以 @Mooophy 的验证代码还没有给出问题的本质,根本不需要50次或是10次,一次就已经失效了。 #include <iostream>
#include <vector>
int main()
{
std::vector<int> iv = {0,1,2,3,4,5,6,7,8,9};
auto iter = iv.begin(), mid = iv.begin() + iv.size()/2;
iv.insert(iter, -1);
std::cout << "capacity = " << iv.capacity() << std::endl;
std::cout << "iter's pos: " << iter - iv.begin() << std::endl; // -12
std::cout << "mid's pos: " << mid - iv.begin() << std::endl; // -7
return 0;
} GCC 4.9.1 这里我自己打自己脸了,上面说“显然”有效,其实一点都不“显然”,上面的代码,可以看到,不仅 mid, 连就在后面一步之遥的 iter 都已经失效了。(想了一下,说失效不准确,应该是未定义行为了) |
Awesome. |
Thx @lafener for issue reporting. |
@pezy , @Mooophy
I think my code is right IMHO, please could you give me any hints? |
Hi @frank67 I must admit that the code in repo looked a little bit misleading. I've updated it like below: #include <iostream>
#include <vector>
void double_and_insert(std::vector<int>& v, int some_val)
{
auto mid = [&]{ return v.begin() + v.size() / 2; };
for (auto curr = v.begin(); curr != mid(); ++curr)
if (*curr == some_val)
++(curr = v.insert(curr, 2 * some_val));
}
int main()
{
std::vector<int> v{ 1, 9, 1, 9, 9, 9, 1, 1 };
double_and_insert(v, 1);
for (auto i : v)
std::cout << i << std::endl;
} I think the point here is iterator invalidation. Your implementation has modified the original code from the exercise too much, such as |
@Mooophy sorry I cannot help you, I don't know what kind of object is
given these value:
your code returns:
mine instead:
I tried to increment
but I got seg-fault at runtime, sorry again:confounded: |
It's not a bug.. |
@frank67
From the code above, we may interpret author's original abstraction intention in two different ways:
IMHO, your code was implementing the first interpretation, whereas mine the second. That's why I was using a function object for Thx for contribution. |
Ok, you can also consider to change the Pezy code applying this 2 lines patch to the
In order to choice the first interpretation, otherwise if you prefer to recalculate the middle iterator each for-loop then your code will be fine. But it looks like to me that it isn't a required feature from the exercise. |
I wanna ask everyone a question. Whether the iterator iter is changed. According to the problem9.22,the iter is not assigned after insertion operation, so i think iter is not changed, thus after the first insertion, the iter is invalidate. |
"iter" doesn't appear in the provided exercise's solution https://github.com/Mooophy/Cpp-Primer/blob/master/ch09/ex9_22.cpp what code are you asking for comments? |
exercise 9.22 in 《c ++ primer》 |
Yes, of course, you cannot test for equality iterators of a container that it grows (if you not previously reassigned these) because it could be reallocated. |
awesome!!!I have learnt so much. |
I think we can use the iv.end() is also ok
|
除了
iter
的值没有改变以外,是否还有迭代器失效的问题?毕竟发生了insert操作。表9.5中说,向一个vector、string或者deque中插入元素会使得所有指向容器的迭代器、引用和指针失效。
The text was updated successfully, but these errors were encountered: