chr*_*ris 11 c++ iterator stl undefined-behavior stl-algorithm
受这个问题的启发,询问如何将一个向量附加到自身,我的第一个想法是以下(是的,我意识到insert现在是一个更好的选择):
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
int main() {
std::vector<int> vec {1, 2, 3};
std::copy (std::begin (vec), std::end (vec), std::back_inserter (vec));
for (const auto &v : vec)
std::cout << v << ' ';
}
Run Code Online (Sandbox Code Playgroud)
但是,这打印:
1 2 3 1 * 3
Run Code Online (Sandbox Code Playgroud)
每次运行程序时*都是不同的数字.只有2被替换的事实是特殊的,如果真的有解释,我会有兴趣听到它.继续,如果我附加到不同的向量(原始副本),它会正确输出.如果我在前一行之前添加以下行,它也会正确输出copy:
vec.reserve (2 * vec.size());
Run Code Online (Sandbox Code Playgroud)
std::back_inserter尽管事先没有预留内存,但我认为这是一种将元素添加到容器末端的安全方法.如果我的理解是正确的,复制线有什么问题?
我假设它与编译器无关,但我使用的是GCC 4.7.1.
Jam*_*lis 12
std::back_inserter创建一个插入迭代器,将元素插入到容器中.每次取消引用此迭代器时,它都会调用push_back容器将新元素追加到容器中.
对于std::vector容器,调用push_backwhere v.size() == v.capacity()将导致重新分配:创建一个新数组来存储向量的内容,将其当前内容复制到新数组中,并销毁旧数组.此时向量中的任何迭代器都将失效,这意味着它们无法再使用.
在程序中,这包括由限定的输入范围begin(vec)和end(vec)从该copy算法被复制.该算法继续使用这些迭代器,即使它们无效,因此您的程序显示未定义的行为.
即使你的容器有足够的容量,它的行为仍然是未定义的:规范说明,在插入时,"如果没有重新分配,插入点之前的所有迭代器和引用都保持有效"(C++11§23.3.6.5)/1).
调用push_back相当于最后插入,因此std::end(vec)传入的结束iterator()std::copy在单次调用后失效push_back.如果输入范围是非空的,则程序显示未定义的行为.
请注意,如果使用a std::deque<int>或a std::list<int>,程序的行为将被很好地定义,因为当附加元素时,这些容器都不会使迭代器无效.
| 归档时间: |
|
| 查看次数: |
1347 次 |
| 最近记录: |