使用自动时不检查数组范围

时间:2019-06-03 13:52:10

标签: c++ clang clang++

使用-Warray-bounds编译this code时。声明array2 array index 3 is past the end of the array (which contains 3 elements)时收到警告。但是,在声明array1时,即使它必须是相同的类型,从而携带相同的大小信息,也并非如此。这是c中的错误吗?

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];
}

4 个答案:

答案 0 :(得分:7)

  

即使它必须是相同的类型

您会认为。但是,如果您检查一下,就会发现它们实际上不是同一类型:

.updateProjectionMatrix()
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&`. 声明为array1auto&

答案 1 :(得分:4)

import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { Routes, RouterModule } from '@angular/router'; import { UserAlbumsComponent } from './user-albums.component'; const routes: Routes = [ { path: '**', component: UserAlbumsComponent } ]; @NgModule({ imports: [ CommonModule, RouterModule.forChild(routes) ], declarations: [UserAlbumsComponent] }) export class UserAlbumsModule { } 是一个指针。

使用array1代替那里的auto&&

答案 2 :(得分:4)

  

但即使必须是相同的类型,也不会在第16行

假设是指auto array1 = AllFormats(),则它的类型不同。永远不会推论auto为参考,因此array1不是参考。它是一个非引用,并被推论为衰减的结果,即指向Format的指针。

由于指针类型不包含有关指针数组大小的信息,因此编译器无法证明下标运算符会使数组溢出。

要声明引用,可以使用以下任一方法:

auto&          array1 = AllFormats(); // 1.
auto&&         array1 = AllFormats(); // 2.
decltype(auto) array1 = AllFormats(); // 3.
  1. 显式声明一个左值引用。
  2. 声明一个通用引用,该通用引用折叠为一个左值引用,因为AllFormats返回一个左值引用。如果AllFormats返回Format&&,它将是一个右值引用。
  3. auto类型推导使用与decltype推导不同的规则。一个主要区别是auto决不是引用,而decltype(E);可能是引用,具体取决于表达式Edecltype(auto) var = E允许使用decltype规则进行声明,就像使用decltype(E)一样。

答案 3 :(得分:2)

auto array1 = AllFormats();    
auto v3 = array1[3];

array1不是数组,因此无法检查范围。即使您通过引用返回,auto也不会演绎一个,因此数组会衰减为一个指针,而array1会推导为Format *

Format (&array2)[3] = AllFormats();    
v3 = array2[3];

生成警告,因为array2是对数组的引用,因此它知道大小。


要让auto推导一个数组,您需要使用auto&(仅在返回的是左值引用时有效),或使用auto&&(将引用绑定到)任何东西。