我曾经接受过一次采访,并被问到通过引用分配变量的目的是什么(如下例所示):
int i = 0;
int &j = i;
我的回答是C ++引用像C指针一样工作,但是不能假设NULL值,它们必须始终指向内存中的具体对象。当然,使用引用时语法不同(不需要指针间接运算符,对象属性将通过点(。)而不是箭头( - >)运算符访问)。也许最重要的区别是,与指针不同,你可以使指针指向不同的东西(即使它指向与另一个指针相同的东西),带引用,如果一个引用被更新,那么其他引用指向相同的东西也被更新为指向同一个对象。
然后我继续说上面引用的使用是没用的(也许这就是我出错的地方),因为我看不到通过引用分配的实际优势:因为两个引用都结束了指出同样的事情,你可以很容易地用一个参考,并且不能想到这种情况不是这样的情况。我接着解释了引用作为传递参考函数参数很有用,但在赋值中却没有用。但是面试官说他们一直在他们的代码中通过引用分配,并且不及我(然后我继续为一家公司工作,这家公司是客户的,但除了这一点之外)。
无论如何,几年后,我想知道我哪里出错了。
答案 0 :(得分:3)
首先,我希望这家公司的缘故不是他们没有聘请你的唯一原因,因为这是一个小小的细节(不,你真的不知道为什么公司没有''雇用你)。
正如评论中所提到的,参考文献永远不会改变他们在生命中所指的内容。一旦设置,引用就会引用相同的位置,直到它“死亡”。
现在,引用对于简化表达式非常有用。假设我们有一个具有相当复杂内容的类或结构。说这样的话:
struct A
{
int x, y, z;
};
struct B
{
A arr[100];
};
class C
{
public:
void func();
B* list[20];
};
void C::func()
{
...
if (list[i]->arr[j].x == 4 && list[i]->arr[j].y == 5 &&
(list[i]->arr[j].z < 10 || list[i]->arr[j].z > 90))
{
... do stuff ...
}
}
那里有很多list[i]->arr[j]
的重复。所以我们可以使用引用重写它:
void C::func()
{
...
A &cur = list[i]->arr[j];
if (cur.x == 4 && cur.y == 5 &&
(cur.z < 10 || cur.z > 90))
{
... do stuff ...
}
}
上面的代码假设do stuff
实际上是以某种方式对cur
元素进行了制作,如果没有,您应该使用const A &cur =...
代替。
我使用这种技术可以使它更清晰,重复性更低。
答案 1 :(得分:2)
在这种在同一范围内为基本类型的局部变量分配引用的特殊情况下,赋值非常无用:使用j
无法使用i
做任何事情都无法使用{{ 1}}。这也有一些轻微的负面影响,因为可读性会受到影响,优化器可能会感到困惑。
以下是分配引用的合法用法:
class demo {
private:
map<int,string> cache;
string read_resource(int id) {
string resource_string;
... // Lengthy process for getting a non-empty resource string
return resource_string;
}
public:
string& get_by_id(int id) {
// Here is a nice trick
string &res = cache[id];
if (res.size() == 0) {
// Assigning res modifies the string in the map
res = read_resource(id);
}
return res;
}
};
上面,引用类型的变量res
是指要么检索或创建新的地图元素。如果字符串是新建的,则代码调用&#34; real&#34; getter,并将其结果分配给res
。这也会自动更新缓存,从而在cache
地图中保存了另一个查找。