我发现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尝试过这个。
答案 0 :(得分:11)
未定义行为的典型示例。
您只能被允许通过索引(使用operator[]
)在0和v.size()-1
(包括)之间访问元素。
使用reserve
不会修改大小,只会修改容量。您是否已使用resize
代替它,它会按预期工作。
答案 1 :(得分:5)
在第一种情况下,您有未定义的行为。 reserve
设置容量,但将 size 保留为零。然后,您的循环将写入向量末尾之外的无效位置。使用(无效)指针进行打印似乎有效(尽管不能保证),因为您已将字符串写入其指向的内存;使用迭代器范围打印什么都不打印,因为矢量仍然是空的。
第二个循环每次都正确地增加了大小,因此向量实际上包含了预期的内容。
使用[]时为什么不更新end()?如果这是故意的,那么它的工作原理是什么?
[]
旨在尽可能快,因此不进行范围检查。如果要进行范围检查,请使用at()
,这将在超出范围的访问中引发异常。如果要调整阵列大小,则必须自己完成。