为什么引用数组是非法的?
下面的代码不能编译。
int a = 1, b = 2, c = 3; int& arr[] = {a,b,c,8};
C ++标准对此有何评论?
我知道我可以声明一个包含引用的类,然后创build该类的数组,如下所示。 但我真的想知道为什么上面的代码不能编译。
struct cintref { cintref(const int & ref) : ref(ref) {} operator const int &() { return ref; } private: const int & ref; void operator=(const cintref &); }; int main() { int a=1,b=2,c=3; //typedef const int & cintref; cintref arr[] = {a,b,c,8}; }
可以使用struct cintref
而不是const int &
来模拟一个引用数组。
C ++标准8.3.2 / 4 :
应该没有对引用的引用, 没有引用数组 ,也没有指向引用的指针。
引用不是对象。 他们没有自己的存储空间,只是参考现有的对象。 因为这个原因,引用数组是没有意义的。
如果你想要一个轻量级的对象引用另一个对象,那么你可以使用一个指针。 如果为所有struct
实例的所有引用成员提供显式初始化,则只能将具有引用成员的struct
用作数组中的对象。 参考资料不能默认initalized。
编辑:正如jia3ep注意到的,在声明的标准部分有一个明确的禁止引用数组。
这是一个有趣的讨论。 很明显,裁判arrays是非法的,但恕我直言之所以没有说“他们不是对象”或“他们没有规模”这么简单。 我想指出,在C / C ++中,数组本身并不是完整的对象 – 如果您反对,可以尝试使用数组作为“类”模板参数来实例化一些stl模板类,然后看看会发生什么。 你不能返回它们,分配它们,把它们作为parameter passing。 (一个数组参数被视为一个指针)。 但是制作数组数组是合法的。 引用具有编译器可以并且必须计算的大小 – 不能sizeof()引用,但是可以创build一个只包含引用的结构体。 它的大小足以包含所有实现引用的指针。 如果不初始化所有成员,则不能实例化这样的结构:
struct mys { int & a; int & b; int & c; }; ... int ivar1, ivar2, arr[200]; mys my_refs = { ivar1, ivar2, arr[12] }; my_refs.a += 3 ; // add 3 to ivar1
实际上,您可以将此行添加到结构定义中
struct mys { ... int & operator[]( int i ) { return i==0?a : i==1? b : c; } };
…现在我有一些看起来像很多的裁判:
int ivar1, ivar2, arr[200]; mys my_refs = { ivar1, ivar2, arr[12] }; my_refs[1] = my_refs[2] ; // copy arr[12] to ivar2 &my_refs[0]; // gives &my_refs.a == &ivar1
现在,这不是一个真正的数组,它是一个运算符重载; 例如,它不会像数组sizeof(arr)/ sizeof(arr [0])那样执行数组的操作。 但它正是我想要一个引用的数组,做完全合法的C ++。 除了(a)设置超过3或4个元素是一种痛苦,并且(b)它正在使用一堆?:进行计算,这可以通过索引来完成(而不是使用正常的C指针计算 – 语义索引,但是索引)。 我想看到一个非常有限的“参考数组”types,实际上可以做到这一点。 也就是说,一个引用数组不会被视为一个引用的事物的一般数组,而是一个新的“引用数组”,它有效地映射到一个内部生成的类,类似于上面的(但是你不幸的是不能与模板)。
这可能会工作,如果你不介意这种讨厌的话:recast'* this'作为一个int *的数组,并返回一个引用:(不推荐,但它显示了如何正确的'数组'会工作):
int & operator[]( int i ) { return *(reinterpret_cast<int**>(this)[i]); }
评论您的编辑:
更好的解决办法是std::reference_wrapper
。
详情: http : //www.cplusplus.com/reference/functional/reference_wrapper/
例:
#include <iostream> #include <functional> using namespace std; int main() { int a=1,b=2,c=3,d=4; using intlink = std::reference_wrapper<int>; intlink arr[] = {a,b,c,d}; return 0; }
一个数组可以隐式地转换成一个指针,而指针指向在C ++中是非法的
因为像这里所说的很多,引用不是对象。 他们只是别名。 确实有些编译器可能会将它们作为指针来实现,但标准并不强制/指定它。 而且因为引用不是对象,所以你不能指向它们。 将元素存储在数组中意味着有某种索引地址(即指向某个索引处的元素); 这就是为什么你不能有引用数组,因为你不能指向它们。
使用boost :: reference_wrapper或boost :: tuple; 或者只是指针。
给定int& arr[] = {a,b,c,8};
什么是sizeof(*arr)
?
其他地方,引用被视为简单的东西本身,所以sizeof(*arr)
应该只是sizeof(int)
。 但是这会使数组的指针algorithm错误(假设引用不是相同的宽度是整数)。 为了消除歧义,这是禁止的。
你可以很接近这个模板结构。 但是,您需要使用指向T的expression式进行初始化,而不是T; 所以,虽然你可以很容易的做一个'fake_constref_array',但是你不能像OP的例子('8')那样把它绑定到rvalues。
#include <stdio.h> template<class T, int N> struct fake_ref_array { T * ptrs[N]; T & operator [] ( int i ){ return *ptrs[i]; } }; int A,B,X[3]; void func( int j, int k) { fake_ref_array<int,3> refarr = { &A, &B, &X[1] }; refarr[j] = k; // :-) // You could probably make the following work using an overload of + that returns // a proxy that overloads *. Still not a real array though, so it would just be // stunt programming at that point. // *(refarr + j) = k } int main() { func(1,7); //B = 7 func(2,8); // X[1] = 8 printf("A=%d B=%d X = {%d,%d,%d}\n", A,B,X[0],X[1],X[2]); return 0; }
– > A = 0 B = 7 X = {0,8,0}
引用对象没有大小。 如果你写了sizeof(referenceVariable)
,它会给你referenceVariable referenceVariable
的对象的大小,而不是引用本身的大小。 它没有自己的大小,这就是为什么编译器不能计算数组的大小需要多less。
考虑一个指针数组。 指针确实是一个地址; 所以当你初始化数组的时候,你就类似地告诉计算机“分配这块内存来存放这些X号码(这些号码是其他项目的地址)”。 那么如果你改变了一个指针,你只是改变它指向的东西; 它仍然是一个数字地址,它本身坐在同一个地方。
引用类似于别名。 如果你要声明一个引用数组,你基本上会告诉计算机,“分配这个由散布在周围的所有这些不同项目组成的内存块”。
当你在数组中存储某些东西时,它的大小需要被知道(因为数组索引依赖于大小)。 根据C ++标准没有指定引用是否需要存储,因为索引数组是不可能的。
只是添加到所有的谈话。 由于数组需要连续的内存位置来存储项目,所以如果我们创build一个引用数组,那么不能保证它们将在连续的内存位置,因此访问将是一个问题,因此我们甚至不能将所有的math运算应用于arrays。
实际上,这是C和C ++语法的混合体。
您应该使用纯C数组,因为引用只是C ++的一部分,所以不能作为引用。 或者你去C ++的方式,并使用std::vector
或std::array
类为您的目的。
至于编辑过的部分:尽pipestruct
是C中的一个元素,但是您可以定义一个构造函数和运算符函数,使其成为一个C ++ class
。 因此,你的struct
不会在纯C中编译!
一个简单的原因引用数组不能存在! 引用是编译时间实体。 这意味着它们在编译时被replace为适当的地址。 现在说你所做的和数组array []。
还有一些在代码中的数组[2],那就没问题了。 编译器只需查看数组中的第三个初始化程序并replace地址即可。
但现在说你做了arrays[我],它将取代什么? 没有关于我的信息。
指针的情况是不同的。 它们是分配给它们的内存的实际variables,如果你执行了*指针,它们将在运行时被parsing。 因此,如果你有一个指针数组,并做*数组[我],这将是有效的,因为有执行过程中有关于我的信息。
我希望它能回答这个问题。