Reason(原因)
(pointer, size)-style interfaces are error-prone. Also, a plain pointer (to array) must rely on some convention to allow the callee to determine the size.
指针+大小风格的接口容易引发错误。同时,(指向数组的)单纯指针必须根据某些惯例被调用者推测(数组的)大小。
Example(示例)
Consider(考虑如下代码):
void copy_n(const T* p, T* q, int n); // copy from [p:p+n) to [q:q+n)
What if there are fewer than n
elements in the array pointed to by q
? Then, we overwrite some probably unrelated memory. What if there are fewer than n
elements in the array pointed to by p
? Then, we read some probably unrelated memory. Either is undefined behavior and a potentially very nasty bug.
如果q指向的数组中的元素数目少于n时会发生什么?答案是会覆盖一些可能无关的内存。如果p指向的数组中元素的个数少于n会怎么样?答案是会读取某些无关的内存。无论哪种情况都是没有定义的行为,并且可能会引起严重的错误。
译者注:这类错误的难点在于发生问题的位置和引入问题的位置不知道离多远,还有可能发生的问题每次都不一样。
Alternative(可选项)
Consider using explicit spans:
考虑使用清晰的span:
void copy(span r, span r2); // copy r to r2
Example, bad(反面示例)
Consider(考虑以下代码):
void draw(Shape* p, int n); // poor interface; poor code
Circle arr[10];
// ...
draw(arr, 10);
Passing 10
as the n
argument may be a mistake: the most common convention is to assume [0:n)
but that is nowhere stated. Worse is that the call of draw()
compiled at all: there was an implicit conversion from array to pointer (array decay) and then another implicit conversion from Circle
to Shape
. There is no way that draw()
can safely iterate through that array: it has no way of knowing the size of the elements.
向形参n传递10可能引发错误:最一般的惯例是假设[0:n)(左闭右开),但是哪里也没有说明。最不好的是对draw()的调用的编译行为:这里有一个从数组到指针的隐式转换(数组退化)和从Circle到Shape的隐式转换。draw()没有办法安全地遍历该数组,因为它无法知道元素的个数。
译者注:draw函数既没有办法知道数组的大小,也没有办法知道元素的类型。
Alternative: Use a support class that ensures that the number of elements is correct and prevents dangerous implicit conversions. For example:
可选项:使用确保元素数量的正确性并可以避免危险的隐式转换的支持类。例如:
void draw2(span
); Circle arr[10];
// ...
draw2(span
(arr)); // deduce the number of elements draw2(arr); // deduce the element type and array size
void draw3(span
); draw3(arr); // error: cannot convert Circle[10] to span
This draw2()
passes the same amount of information to draw()
, but makes the fact that it is supposed to be a range of Circle
s explicit.
draw2()(的两次调用)会向draw传递相同数量的信息。形成这个结果的原因是(draw2函数)会推断它的参数是Circles的range。
See ???.
参考T.B.D(译者注:作者还没想好)
Exception(例外)
Use zstring
and czstring
to represent C-style, zero-terminated strings. But when doing so, use std::string_view
or string_span
from the GSL to prevent range errors.
使用zstring和czstring来代替C风格,以0结尾的字符串。这种情况下使用来自GSL的str::string_view或者string_span以避免range错误。
译者注:这种情况下使用span会发生错误。
Enforcement(实施建议)
(简单)((范围))任何表达式包含了从数组到指针的隐式转换,报警。作为例外,允许zstring/czstring类型的指针。
(简单)((范围))如果对指针的表达式进行算数操作并产生一个指针值,报警。指针类型为zstring/czstring时可以作为例外。