默认情况下,为什么 C++ 不检测何时使用 [ ] 运算符访问超出范围的向量元素?
Why doesn't C++ detect when out of range vector elements are accessed with the [ ] operators by default?
我知道数组是原始数组 class,因此没有内置方法来检测超出范围的错误。然而,向量 class 有内置函数 .at() 可以检测到这些错误。通过使用名称空间,任何人都可以重载 [ ] 符号以充当 .at() 函数,方法是在访问向量范围之外的值时抛出错误。我的问题是:为什么这个功能在 C++ 中不是默认的?
编辑:下面是重载向量运算符 [ ]:
的伪代码示例(我相信 - 如果需要请纠正我)
Item_Type& operator[](size_t index) { // Verify that the index is legal.
if (index < 0 || index >= num_items) {
throw std::out_of_range
("index to operator[] is out of range");
}
return the_data[index]
}
我相信这个函数可以写入用户定义的命名空间并且相当容易实现。如果这是真的,为什么它不是默认值?
C++ 有一个只为使用付费的原则。因此,未经检查的操作肯定有一席之地;仅仅因为你懒得注意你的边界并不意味着我应该付出性能损失。
历史上数组 []
在 C 和 C++ 中都未被选中。仅仅因为年轻 10-20 岁的语言进行了检查操作并不意味着 C++ 需要进行这种基本的向后不兼容的更改。
对于通常与 []
一样便宜的东西,边界检查会增加大量开销。
考虑
int f1(const std::vector<int> & v, std:size_t s) { return v[s]; }
这个函数转换为just three lines of assembly:
movq (%rdi), %rax
movl (%rax,%rsi,4), %eax
ret
现在考虑使用 at()
的边界检查版本:
int f2(const std::vector<int> & v, std:size_t s) { return v.at(s); }
这变成了
movq (%rdi), %rax
movq 8(%rdi), %rdx
subq %rax, %rdx
sarq , %rdx
cmpq %rdx, %rsi
jae .L6
movl (%rax,%rsi,4), %eax
ret
.L6:
pushq %rax
movl $.LC1, %edi
xorl %eax, %eax
call std::__throw_out_of_range_fmt(char const*, ...)
即使在正常(非抛出)代码路径中,也有 8 行汇编 - 几乎是原来的三倍。
我知道数组是原始数组 class,因此没有内置方法来检测超出范围的错误。然而,向量 class 有内置函数 .at() 可以检测到这些错误。通过使用名称空间,任何人都可以重载 [ ] 符号以充当 .at() 函数,方法是在访问向量范围之外的值时抛出错误。我的问题是:为什么这个功能在 C++ 中不是默认的?
编辑:下面是重载向量运算符 [ ]:
的伪代码示例(我相信 - 如果需要请纠正我)Item_Type& operator[](size_t index) { // Verify that the index is legal.
if (index < 0 || index >= num_items) {
throw std::out_of_range
("index to operator[] is out of range");
}
return the_data[index]
}
我相信这个函数可以写入用户定义的命名空间并且相当容易实现。如果这是真的,为什么它不是默认值?
C++ 有一个只为使用付费的原则。因此,未经检查的操作肯定有一席之地;仅仅因为你懒得注意你的边界并不意味着我应该付出性能损失。
历史上数组 []
在 C 和 C++ 中都未被选中。仅仅因为年轻 10-20 岁的语言进行了检查操作并不意味着 C++ 需要进行这种基本的向后不兼容的更改。
对于通常与 []
一样便宜的东西,边界检查会增加大量开销。
考虑
int f1(const std::vector<int> & v, std:size_t s) { return v[s]; }
这个函数转换为just three lines of assembly:
movq (%rdi), %rax
movl (%rax,%rsi,4), %eax
ret
现在考虑使用 at()
的边界检查版本:
int f2(const std::vector<int> & v, std:size_t s) { return v.at(s); }
这变成了
movq (%rdi), %rax
movq 8(%rdi), %rdx
subq %rax, %rdx
sarq , %rdx
cmpq %rdx, %rsi
jae .L6
movl (%rax,%rsi,4), %eax
ret
.L6:
pushq %rax
movl $.LC1, %edi
xorl %eax, %eax
call std::__throw_out_of_range_fmt(char const*, ...)
即使在正常(非抛出)代码路径中,也有 8 行汇编 - 几乎是原来的三倍。