为什么 &x[0]+x.size() 而不是 &x[x.size()]?
Why &x[0]+x.size() instead of &x[x.size()]?
我正在阅读 C++ 之旅(第 2 版),并且遇到了这段代码(6.2 参数化类型):
template<typename T>
T* end(Vector<T>& x)
{
return x.size() ? &x[0]+x.size() : nullptr; // pointer to one-past-last element
}
我不明白为什么我们使用 &x[0]+x.size()
而不是 &x[x.size()]
。这是否意味着我们获取 x
中的第一个元素的地址并仅添加到该数字 x.size()
字节?
&x[x.size()]
会导致(试图)获取 x[x.size()]
的地址。但是 x[x.size()]
尝试访问越界元素;根据特定 T
的 Vector<T>::operator[]
的 API,可能会发生一些不好的事情:
| Vector<T>::operator[] semantics |
| ======================================= |
| return\ contr | | |
| type \ -act | unchecked | checked |
| --------------------------------------- |
| reference | UB (1) | FH |
| value | UB (2) | FH |
| --------------------------------------- |
和
- UB (1):创建对 out-of-range-element.
的引用时的未定义行为
- UB (2):尝试读取 out-of-range 元素的值时出现未定义的行为。
- FH:来自 API 的某些错误处理操作(如果已检查)(例如抛出异常、终止...)。
对于 std::vector
,例如,您将 运行 放入 UB (1),因为它的 operator[]
未选中并且 returns 是引用类型。
虽然您可以执行指针算法来计算指向缓冲区的 one-past-last(语义上 end()
)的指针,但您不能取消引用 one-past-last 指针。
我正在阅读 C++ 之旅(第 2 版),并且遇到了这段代码(6.2 参数化类型):
template<typename T>
T* end(Vector<T>& x)
{
return x.size() ? &x[0]+x.size() : nullptr; // pointer to one-past-last element
}
我不明白为什么我们使用 &x[0]+x.size()
而不是 &x[x.size()]
。这是否意味着我们获取 x
中的第一个元素的地址并仅添加到该数字 x.size()
字节?
&x[x.size()]
会导致(试图)获取 x[x.size()]
的地址。但是 x[x.size()]
尝试访问越界元素;根据特定 T
的 Vector<T>::operator[]
的 API,可能会发生一些不好的事情:
| Vector<T>::operator[] semantics |
| ======================================= |
| return\ contr | | |
| type \ -act | unchecked | checked |
| --------------------------------------- |
| reference | UB (1) | FH |
| value | UB (2) | FH |
| --------------------------------------- |
和
- UB (1):创建对 out-of-range-element. 的引用时的未定义行为
- UB (2):尝试读取 out-of-range 元素的值时出现未定义的行为。
- FH:来自 API 的某些错误处理操作(如果已检查)(例如抛出异常、终止...)。
对于 std::vector
,例如,您将 运行 放入 UB (1),因为它的 operator[]
未选中并且 returns 是引用类型。
虽然您可以执行指针算法来计算指向缓冲区的 one-past-last(语义上 end()
)的指针,但您不能取消引用 one-past-last 指针。