您的问题非常广泛,因此很难正确回答。在概念上,引用是对象的别名。特定编译器如何实现此概念可能会有所不同,尤其是在优化之后。在许多情况下,实现本质上使用指向对象的指针,在这种情况下,引用需要内存,而存储在那里的可能只是对象的地址。
struct S1{
int & ri;
S1(int &i):ri{i}{}
};
在这种情况下,我希望编译器需要内存来保存引用。
struct S2{
int i;
int& ri;
S2():ri{i}{}
};
在这种情况下,引用可能不需要内存。
归根结底,不能依赖特定版本中的特定编译器处理引用的方式。
您是否将引用视为别名或指针,它必须始终指向一个对象(即永远不会为 nullptr)并且始终指向同一个对象(即 const)并且在您自己对一块的理解中自动取消引用代码可能并不重要。
虽然可以创建一个“空引用”,例如
int *i= nullptr;
int& ri=*i;
这是未定义的行为,如下所述:Assigning a reference by dereferencing a NULL pointer
未定义的行为意味着任何事情都可能发生,看起来在您的编译器上引用仍然像空指针一样,但是这里有一些编译器可能会非常奇怪的例子(并且允许在没有错误或警告的情况下)
int i;
//...
if(&i) {} //always true
else {
//optimized away
}
int* i;
//...
if(i){}
else{
//not optimized away
}
int *i = nullptr;
int& ri = *i;
//...
if(&ri){} //could be assumed always true!
else{
//could be optimized away !!
}
int *i =nullptr;
*i++; //runtime error, convention says user should have checked for nullness
int& ri = i;
ri++; //probably runtime error, user does not know to check for nullness and may not be able to because of optimization assuming &ri ! nullptr
struct S{
int i[1001];
};
S* s = nullptr;
S& rs = *s;
if(&rs){ //could be assume always true
rs.i[1000] = 4; //may not result in runtime error, address could be 0x4000,
// probably still not valid on a pc, on an embedded processor you could be
// changing clock speed or something nasty even though you checked for
// nullness!!!! Undefined behavior sucks!
}