我理解为什么会导致段错:
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
vector<int> v;
int iArr[5] = {1, 2, 3, 4, 5};
int *p = iArr;
copy(p, p+5, v.begin());
return 0;
}
但为什么这不会导致段错?
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
vector<int> v;
int iArr[5] = {1, 2, 3, 4, 5};
int *p = iArr;
v.reserve(1);
copy(p, p+5, v.begin());
return 0;
}
答案 0 :(得分:7)
这是未定义的行为 - reserve()
为分配一个缓冲区,至少一个元素,并且该元素未被初始化。
所以要么缓冲区足够大,所以你在技术上可以访问第一个之外的元素,或者它不够大,你恰好没有发现任何问题。
底线是 - 不要这样做。仅访问合法存储在vector
实例中的元素。
答案 1 :(得分:7)
两者都错了,因为您要复制到空矢量并且复制要求您有空间进行插入。它不会自行调整容器大小。你可能需要的是back_insert_iterator和back_inserter:
copy(p, p+5, back_inserter(v));
答案 2 :(得分:2)
这是错的!访问您不拥有的内存是未定义的行为,即使它在一个示例中有效。我认为,原因是std::vector
会保留多个元素。
答案 3 :(得分:2)
但为什么这不会导致 段错误?
因为星星对齐了。或者你在调试中运行,编译器做了一些“帮助”你的事情。底线是你做错了什么,并且进入了未定义行为的黑暗和不确定的世界。您reserve
向量中的一个点,然后尝试将5个元素填入reserve
- ed空间。坏。
您有3个选项。按照我个人的偏好顺序:
1)使用专为此目的而设计的back_insert_iterator
。它由#include <iterator>
提供。语法有点时髦,但幸运的是,还提供了一个很好的糖衣快捷方式back_inserter
:
#include <iterator>
// ...
copy( p, p+5, back_inserter(v) );
2)assign
向量的元素。我更喜欢这种方法,因为assign
是vector
的成员,这让我感觉不像使用来自algorithm
的某些东西。
v.assign(p, p+5);
3)reserve
正确数量的元素,然后复制它们。我认为这是最后的努力,以防万一其他因任何原因而失败。它依赖于vector
的存储是连续的这一事实,因此它不是通用的,它只是感觉像是将数据传入vector
的后门方法。
答案 4 :(得分:0)
因为你不走运。访问未分配的内存是UB。
答案 5 :(得分:0)
很可能因为空向量根本没有分配任何内存,所以你试图写入一个通常导致即时崩溃的NULL指针。在第二种情况下,它至少分配了一些内存,并且您很可能覆盖数组的末尾,这可能会也可能不会导致C ++崩溃。
两者都错了。
答案 6 :(得分:0)
顺便说一下,即使将1个元素复制到向量中也是错误的(或保留5然后复制那个方式)。
它最有可能不会出现段错误的原因是,实现者认为仅为了一个元素分配内存效率是低效的,以防万一你想在以后增长,所以也许它们可以分配足够的16或32个元素。 / p>
首先执行保留(5)然后直接写入5个元素可能不是未定义的行为但是不正确,因为矢量的逻辑大小不会是5,并且副本几乎会被“浪费”,因为矢量会声称仍然有0的大小。
什么是有效的行为是reserve(5),插入一个元素,在某处存储它的迭代器,插入另外4个元素并查看第一个迭代器的内容。 reserve()保证迭代器在向量超过该大小或者进行诸如erase(),clear(),resize()或其他reserve()之类的调用之前不会失效。