关于以下示例,我有两个问题: 1)
std::vector<int> v(5,1);
cout << *v.end();
打印结果是否未定义(取决于编译器)
2)
int x = 5,y = 6;
std::vector<int*> pv;
pv.push_back(&x);
pv.push_back(&y);
cout << *pv.end();
打印结果是否未定义(取决于编译器)或NULL
答案 0 :(得分:3)
end()
处没有项目,它是向量中最后一个有效项目之后的迭代器。
*v.end();
未定义的行为 。您可以使用end()
来比较迭代器是否指向最后一项之后的项目。
访问上一项值的简便方法是back()
,例如:
cout << v.back();
答案 1 :(得分:2)
end()
迭代器指向一个位置,该位置是容器的最后一个元素之后的元素。访问它指向的数据将调用未定义的行为,这两个示例都是这种情况。
答案 2 :(得分:1)
如果我们查看草案C ++标准部分24.21
迭代器要求,那么结束时取消引用可能会结束很糟糕,但看起来它是实现已定义 >然后转到24.2.1
一般段 5 说(强调我的):
正如指向数组的常规指针一样,保证指针值指向数组的最后一个元素,因此对于任何迭代器类型,都有一个迭代器值指向相应序列的最后一个元素。这些值称为past-the-end值。 定义表达式 i的迭代器i的值称为可解除引用。库从不假设过去的值是可解除引用的。 迭代器也可以具有与任何序列无关的奇异值。 [示例:在声明未初始化的指针x(与int x;)之后,必须始终假定x具有指针的奇异值。 -end example] 对于奇异值,大多数表达式的结果都是未定义的; [...] 可解除引用的值始终是非单数的。
答案 3 :(得分:1)
首先,在这两种情况下,行为都是未定义的。注意,这不是未定义的“打印结果”。您的代码甚至没有机会打印任何东西。仅仅*
运算符应用于结束迭代器已经导致未定义的行为。例如。仅此一点
*v.end();
已经是未定义的行为。
其次,在这种情况下未定义并不意味着“取决于编译器”。 实现定义的行为取决于编译器。 未定义表示“完全不可预测”,即使您使用的是相同的编译器。
P.S。在标准委员会中似乎有一些正在进行的工作,需要注意一些密切相关的问题。
http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#208
http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#1213
希望它能够更清晰地说明什么是合法的,什么不适合过去的迭代器。但很明显,在一般情况下,past-the-end迭代器在法律上可以是一个单一的迭代器,这意味着在一般情况下它可以是不可解除引用的。
答案 4 :(得分:0)
是的,这两个都是未定义的。
答案 5 :(得分:0)
vector::end
- 将迭代器返回到end(公共成员函数)
您可以阅读更多here。
第一个例子:
std::vector<int> v(5,1);
cout << *(v.end()-1);
未定义(查看图片),v.end()
指向最后一个元素后的地址,如果容器为空,则此函数返回与{{1}相同的地址}。
您的第二个例子:
v.begin()