访谈:按引用分配的实际用途(而不是通过参考传递)

时间:2015-02-08 14:18:34

标签: c++ reference variable-assignment assignment-operator assign

我曾经接受过一次采访,并被问到通过引用分配变量的目的是什么(如下例所示):

int i = 0;

int &j = i;

我的回答是C ++引用像C指针一样工作,但是不能假设NULL值,它们必须始终指向内存中的具体对象。当然,使用引用时语法不同(不需要指针间接运算符,对象属性将通过点(。)而不是箭头( - >)运算符访问)。也许最重要的区别是,与指针不同,你可以使指针指向不同的东西(即使它指向与另一个指针相同的东西),带引用,如果一个引用被更新,那么其他引用指向相同的东西也被更新为指向同一个对象。

然后我继续说上面引用的使用是没用的(也许这就是我出错的地方),因为我看不到通过引用分配的实际优势:因为两个引用都结束了指出同样的事情,你可以很容易地用一个参考,并且不能想到这种情况不是这样的情况。我接着解释了引用作为传递参考函数参数很有用,但在赋值中却没有用。但是面试官说他们一直在他们的代码中通过引用分配,并且不及我(然后我继续为一家公司工作,这家公司是客户的,但除了这一点之外)。

无论如何,几年后,我想知道我哪里出错了。

2 个答案:

答案 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地图中保存了另一个查找。