使用自动时不检查数组边界
No array bounds check when using auto
当 this code 与 -Warray-bounds
编译时。我在声明 array2 array index 3 is past the end of the array (which contains 3 elements)
时收到警告。但不是在声明 array1 时,即使它必须是相同的类型,因此携带相同的大小信息。这是 clang 中的错误吗?
enum class Format : int {
Off = 55,
FormatA = 66,
FormatB = 77,
};
inline Format (&AllFormats())[3] {
static Format values[] = {
Format::Off,
Format::FormatA,
Format::FormatB
};
return values;
}
int main()
{
auto array1 = AllFormats();
auto v3 = array1[3];
Format (&array2)[3] = AllFormats();
v3 = array2[3];
}
array1
是一个指针。
在那里使用auto&&
而不是auto
。
even though it has to be the same type
你会这么想的。但是如果你检查一下,你会发现它们实际上不是同一个类型:
std::cout << typeid(array1).name() << "\n";
std::cout << typeid(array2).name() << "\n";
P6Format
A3_6Format
糟糕。 AllFormats
返回的数组在分配给 auto
变量时衰减为指针,因为这就是 auto
的类型推导规则的工作方式。比较:
int& foo() {
static int x = 42;
return x;
}
auto x = foo(); // Type of `x` is `int`, not `int&`.
为防止出现这种情况,请将 array1
声明为 auto&
或 auto&&
。
在
auto array1 = AllFormats();
auto v3 = array1[3];
array1
不是数组,因此无法检查边界。即使您通过引用 return,auto
也不会推导一个,因此数组会衰减为指针,并且 array1
会推导为 Format *
.
Format (&array2)[3] = AllFormats();
v3 = array2[3];
生成警告,因为 array2
是对数组的引用,所以它知道大小。
要让 auto
推导一个数组,您需要使用 auto&
,只有当 returned 是左值引用时才有效,或者 auto&&
这将绑定对任何内容的引用。
But not at line 16 even though it has to be the same type
假设 它 你指的是 auto array1 = AllFormats()
,那么它没有相同的类型。 auto
永远不会被推断为引用,因此 array1
不是引用。它是一个 non-reference,并被推断为衰减结果,即指向 Format
.
的指针
由于指针类型不携带有关指向数组大小的信息,编译器无法证明下标运算符溢出数组。
要声明引用,您可以使用:
auto& array1 = AllFormats(); // 1.
auto&& array1 = AllFormats(); // 2.
decltype(auto) array1 = AllFormats(); // 3.
- 显式声明一个左值引用。
- 声明一个通用引用,它折叠成一个左值引用,因为
AllFormats
returns 一个左值引用。如果 AllFormats
返回 Format&&
. ,它将是一个右值引用
auto
类型推导使用与 decltype
推导不同的规则。一个关键区别是 auto
永远不是引用,而 decltype(E);
可能是引用,具体取决于表达式 E
。 decltype(auto) var = E
允许使用 decltype
规则进行声明,就像使用 decltype(E)
一样。
当 this code 与 -Warray-bounds
编译时。我在声明 array2 array index 3 is past the end of the array (which contains 3 elements)
时收到警告。但不是在声明 array1 时,即使它必须是相同的类型,因此携带相同的大小信息。这是 clang 中的错误吗?
enum class Format : int {
Off = 55,
FormatA = 66,
FormatB = 77,
};
inline Format (&AllFormats())[3] {
static Format values[] = {
Format::Off,
Format::FormatA,
Format::FormatB
};
return values;
}
int main()
{
auto array1 = AllFormats();
auto v3 = array1[3];
Format (&array2)[3] = AllFormats();
v3 = array2[3];
}
array1
是一个指针。
在那里使用auto&&
而不是auto
。
even though it has to be the same type
你会这么想的。但是如果你检查一下,你会发现它们实际上不是同一个类型:
std::cout << typeid(array1).name() << "\n";
std::cout << typeid(array2).name() << "\n";
P6Format
A3_6Format
糟糕。 AllFormats
返回的数组在分配给 auto
变量时衰减为指针,因为这就是 auto
的类型推导规则的工作方式。比较:
int& foo() {
static int x = 42;
return x;
}
auto x = foo(); // Type of `x` is `int`, not `int&`.
为防止出现这种情况,请将 array1
声明为 auto&
或 auto&&
。
在
auto array1 = AllFormats();
auto v3 = array1[3];
array1
不是数组,因此无法检查边界。即使您通过引用 return,auto
也不会推导一个,因此数组会衰减为指针,并且 array1
会推导为 Format *
.
Format (&array2)[3] = AllFormats();
v3 = array2[3];
生成警告,因为 array2
是对数组的引用,所以它知道大小。
要让 auto
推导一个数组,您需要使用 auto&
,只有当 returned 是左值引用时才有效,或者 auto&&
这将绑定对任何内容的引用。
But not at line 16 even though it has to be the same type
假设 它 你指的是 auto array1 = AllFormats()
,那么它没有相同的类型。 auto
永远不会被推断为引用,因此 array1
不是引用。它是一个 non-reference,并被推断为衰减结果,即指向 Format
.
由于指针类型不携带有关指向数组大小的信息,编译器无法证明下标运算符溢出数组。
要声明引用,您可以使用:
auto& array1 = AllFormats(); // 1.
auto&& array1 = AllFormats(); // 2.
decltype(auto) array1 = AllFormats(); // 3.
- 显式声明一个左值引用。
- 声明一个通用引用,它折叠成一个左值引用,因为
AllFormats
returns 一个左值引用。如果AllFormats
返回Format&&
. ,它将是一个右值引用
auto
类型推导使用与decltype
推导不同的规则。一个关键区别是auto
永远不是引用,而decltype(E);
可能是引用,具体取决于表达式E
。decltype(auto) var = E
允许使用decltype
规则进行声明,就像使用decltype(E)
一样。