2011-07-26 36 views
13

注意:我使用的是g ++编译器(这是我听说的非常好,应该是非常接近标准)。当声明对Ints数组的引用时,为什么它必须是对const指针的引用?


比方说,你已经宣布的int数组:

int a[3] = { 4, 5, 6 }; 

现在让我们假设你真的要声明该数组(请不要介意,为什么,除了Bjarne的基准说,语言支持的话)。

案例1 - 如果你尝试:

int*& ra = a; 

则编译梁木,并说:

"invalid initialization of non-const reference of type `int*&' from a temporary of type `int*'" 

首先第一件事情,为什么是 '一个' 临时变量(即不它在内存中的地方吗?)......

反正精细,每当我看到一个非const的错误,我尝试在一个const扔...

案例2 - 如果你尝试:

int*const&rca = a; //wish I knew where the spaces should go (but my other post asking about this sort of protocol got a negative rank while many of the answers got ranked highly -- aha! there are stupid questions!) 

然后一切都很酷,它编译,你会得到的数组的引用。

案例3 - 现在,这里是另一回事,这将编译:

int* justSomeIntPointer = a; //LINE 1 
int*& rpa = justSomeIntPointer; //LINE 2 

这也给了你原来的数组的引用。

所以这里是我的问题:什么时候静态声明的数组 的名称成为常量指针?我似乎记得一个int数组的名字也是一个int指针,但我不记得它曾经是一个const指针int ...

看起来好像情况1因为声明的参考(ra)不是const指针,这可能意味着'a'已经是一个const-pointer-to-int开头。

似乎情况2的工作原理是因为声明的引用(rca)已经是一个const-pointer-to-int。

案例3也有效,它很整洁,但为什么?假定的指针指向int(即数组名称'a')在什么时候成为一个常量指针?将它分配给int *(LINE 1)时会发生吗?或者当您将该int *分配给int * &(LINE 2)时它会发生吗?

希望这是有道理的。谢谢。

回答

27
int*& ra = a; 

int*是一个指针类型,而不是数组类型。所以这就是为什么它不会绑定到a,其类型为int[3]

int* const& ra = a; 

的作品,因为它相当于

int* const& ra = (int*)a; 

也就是说,临时指针的赋值的右手边是概念上创建,然后这个临时势必ra。因此,在端部,这是没有优于:

int* ra = a; 

其中ra事实上是一个指针数组的第一元素,而不是到所述阵列的引用。

声明到数组的引用的简单方法:

typedef int array_type[3]; 
array_type& ra = a; 

的不是如-简单的方法:

int (&ra)[3] = a; 

的C++ 11-简单的方法:

auto& ra = a; 

静态声明数组的名称成为常量指针的哪一点?我似乎记得一个int数组的名称也是一个int指针,但我不记得它曾经是一个const指针int ...

这是正确的问题要问!如果你明白阵列到指针的衰减何时发生,那么你是安全的。简单地说,需要考虑两件事情:当任何一种“复制”的尝试

  • 衰变发生(因为C不允许数组直接复制)
  • 衰变是一种转换,并能发生任何时候允许转换:当类型不匹配时

第一种典型情况发生在模板上。所以给出template<typename T> pass_by_value(T);,然后pass_by_value(a)实际上传递一个int*,因为int[3]类型的数组不能被复制

至于第二个,你已经看到它在行动:这种情况发生在你的第二个案例当int* const&无法绑定到int[3],但可以绑定到临时int*,因此转换发生。

-2

a是一个临时变量,因为您在堆栈中声明了它,而不是在使用malloc或new的堆上声明它。

+0

所以被临时变量总是const的? – Jimmy

+3

@Jimmy:临时表达式并不总是const,但是语言禁止直接绑定到非const引用。数组'a'不是一个临时的,但它是由数组到指针的转换产生的指针,这是一个临时的。 –

+0

在堆栈中声明意味着'具有自动存储持续时间',即当其包含的块/对象确实不在“临时”时超出范围。很少有人考虑必须手动管理动态分配的对象才能成为加分点。我们需要的最后一件事是关于为什么动态分配更好的另一个错误想法。这一点尤其糟糕,因为它引发了_temporary_的错误定义,这个术语具有非常明确的,不同的含义。 –

0

什么时候静态声明的数组的名称成为常量指针?我似乎记得一个int数组的名字也是一个int指针,但我不记得它曾经是一个const指针int ...

因为你写的值在cpp文件中,这就是为什么它是恒定的。

可以只使用:

const int *pToArray = a; 

const int *pToArray = (const int*)&a[0]; 
2

大多数人犯的非常大的错误(也是一个很好的面试问题)是他们认为数组的名字相当于一个指针。这是不正确的。这个错误导致C程序中的许多错误,特别是连接错误,并且它们很难调试。不同之处在于:数组的名称,是一个指针,它是结构的第一个元素,即数组。然而,数组名称的类型不是pointertype,而是数组类型。另一方面,指针只是指向一件事物的指针,没有其他信息。指针的类型是pointertype。数组类型具有其他一些属性,如它知道它是否在堆栈上;因此,“暂时”。你的情况中的临时错误来自一个检查,它阻止了一个临时变量被分配给一个引用。 const关键字将关闭。另一方面,Pointertype没有“临时”的概念。现在假设你想欺骗编译器并为堆栈中的东西分配一个引用。在这种情况下,你需要把它作为一个指针。怎么样?

int * & ra = & a [0];

在上述情况下,您首先获取值并使用&(操作符的地址)您制作pointerType。现在pointertype没有关于它是否在堆栈上(临时变量)的信息。但是,这将引用指向数组第一个元素的指针。 (所以只是一个指针类型,而不是一个数组类型)

1

如果你真的想要一个数组的引用,那么你应该使用下列内容:

int a[3] = { 4, 5, 6 }; 
int (&ra)[3] = a; 

你正在尝试与int *&创建是一个参考到一个指向int的指针。这不是同一类型。而当你用一个不能改变的值初始化参考(数组的地址)时,你必须声明指针const(而不是int)。

1

您有整数数组:

int a[3] = { 4, 5, 6 }; 

现在,这一行:

int*& ra = a; 

创建一个指针的引用。由于您创建了一个临时指针(从数组a转换而来),编译器会抱怨,因为标准禁止将临时对象分配给引用。

因此,要解决这个问题,你需要创建一个指针,然后将其分配给一个指针引用:

int *pa = a; 
int *& rpa = pa; 

经常提到可容纳参考临时工,但你已经发现了这一点。

你问什么(约引用到一个数组) - 有关创建一个数组的引用最著名的例子是这样的:

template< typename T, size_t N > 
size_t ArraySize(T (&)[ N ]) 
{ 
    return N; 
} 

这个函数接受一个数组的引用,并返回它的大小。

8

C++中的“数组”一词拼写为括号[]。如果你想用C++声明一个东西数组,你必须在你的声明中有括号。如果你用星号*代替,你会得到一个指针。指针和数组是两回事。

这是一个数组的引用:

int (&ra) [3] = a; 
相关问题