std :: copy和std :: vector问题

时间:2010-11-10 13:15:33

标签: c++ stl vector

我理解为什么会导致段错:

#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;
}

7 个答案:

答案 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向量的元素。我更喜欢这种方法,因为assignvector的成员,这让我感觉不像使用来自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()之类的调用之前不会失效。