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

mur*_*att 1 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;
}
Run Code Online (Sandbox Code Playgroud)

构建和运行此产生:

$ g++ main.cpp -o v && ./v
&v[0]:     some string
begin/end: 
&v[0]:     some string
begin/end: some string
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

Mat*_* M. 11

未定义行为的典型示例.

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

使用reserve不修改大小,只修改容量.你会使用resize它,它会按预期工作.


Mik*_*our 5

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

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

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

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