什么是这个意想不到的std :: vector行为?

时间:2012-02-01 12:19:15

标签: c++ stl vector

我发现std::vector令人惊讶的事情我认为我会在这里问到希望得到一些有趣的答案。

下面的代码只是将字符串复制到char矢量中,并以两种方式打印矢量的内容。

#include <vector>
#include <string>
#include <iostream>

int main()
{
    std::string s("some string");
    std::vector<char> v;
    v.reserve(s.size()+1);

    // copy using index operator
    for (std::size_t i=0; i<=s.size(); ++i)
        v[i] = s[i];

    std::cout << "&v[0]:     " << &v[0] << "\n";
    std::cout << "begin/end: " << std::string(v.begin(), v.end()) << "\n";

    // copy using push_back
    for (std::size_t i=0; i<=s.size(); ++i)
        v.push_back(s[i]);

    std::cout << "&v[0]:     " << &v[0] << "\n";
    std::cout << "begin/end: " << std::string(v.begin(), v.end()) << "\n";

    return 0;
}

构建并运行此产生:

$ g++ main.cpp -o v && ./v
&v[0]:     some string
begin/end: 
&v[0]:     some string
begin/end: some string

我的期望是它会在两种情况下正确打印字符串,但是使用索引运算符逐字符分配时不会在以后使用begin()时打印任何内容end()迭代器

使用end()时,为什么[]未更新?如果这是故意的,那么它的工作原理是什么?

这种行为有合理的解释吗? :)

到目前为止,我只用gcc 4.6.1尝试过这个。

2 个答案:

答案 0 :(得分:11)

未定义行为的典型示例。

您只能被允许通过索引(使用operator[])在0和v.size()-1(包括)之间访问元素。

使用reserve不会修改大小,只会修改容量。您是否已使用resize代替它,它会按预期工作。

答案 1 :(得分:5)

在第一种情况下,您有未定义的行为。 reserve设置容量,但将 size 保留为零。然后,您的循环将写入向量末尾之外的无效位置。使用(无效)指针进行打印似乎有效(尽管不能保证),因为您已将字符串写入其指向的内存;使用迭代器范围打印什么都不打印,因为矢量仍然是空的。

第二个循环每次都正确地增加了大小,因此向量实际上包含了预期的内容。

  

使用[]时为什么不更新end()?如果这是故意的,那么它的工作原理是什么?

[]旨在尽可能快,因此不进行范围检查。如果要进行范围检查,请使用at(),这将在超出范围的访问中引发异常。如果要调整阵列大小,则必须自己完成。