C ++从具有解除引用类型的函数返回引用?

时间:2014-01-05 18:46:21

标签: c++ reference iterator return

在下面的函数中,我想要一个向量objects并返回该向量的一个元素的副本。由于下面的代码编译正确,我假设迭代器copy_objects.back()被自动解除引用。但我不确定。返回声明中发生了什么?

MyObject best(vector<MyObject>& objects) {
    vector<MyObject> copy_objects = objects;
    sort(copy_objects.begin(), copy_objects.end(), compare_MyObject_func);
    return copy_objects.back();
}

我知道还有其他方法可以完成手头的简单任务,但我很想知道这个例子中发生了什么。


后续问题......

使用上面best函数的定义,我得到以下编译错误:

error: invalid initialization of non-const reference of type ‘std::vector<MyObject>&’ from an rvalue of type ‘std::vector<MyObject>’
     bestObject = best(myfunction(objects));
                                          ^

相关类型声明的位置为:

MyObject bestObject;
vector<MyObject> objects;
vector<MyObject> myfunction(vector<MyObject>&);

我的直觉告诉我这个错误与上面的原始问题有关。但是,我不明白问题是什么。

4 个答案:

答案 0 :(得分:4)

“取消引用”通常是指将一元*运算符应用于指针或其他迭代器(如*p)。这个术语令人困惑,因为它与C ++中的引用类型没有任何关系,因此标准委员会正在转而使用“执行间接”。

无论如何,copy_objects.back()根本不会返回迭代器。它返回对象的引用(实际引用类型)。您可以看到这一点,因为std::vector<T>::back的返回类型是const_reference,它是const value_type&的typedef,其中value_typeT。你永远不会“取消引用”引用。如果要从引用中复制,只需将其视为普通对象即可。

int x = 0;
int& y = x;
int z = y;

在此示例中,z将是xy引用的对象的副本。


除此之外,我建议也按值取值(删除&):

MyObject best(vector<MyObject> objects) {
  sort(objects.begin(), objects.end(), compare_MyObject_func);
  return objects.back();
}

无论如何你都要复制它,所以把它作为参考是毫无意义的。特别是非const引用表明您将修改给定的参数,而不是。实际上,当vector可以移动到函数中时,参考参数会给您带来更差的性能。参考类型参数永远不会移动。


回答您延伸的问题:

myfunction按值返回,这意味着它返回的对象是一个临时对象(它是其中任何内容的副本)。您不能将非const引用(best的参数)绑定到临时对象。这是有道理的,因为那时临时对象会消失(因为它是临时的)并且引用将留下什么都没有。

如果您将参数类型设为const引用,那就没问题,因为const引用会延长临时对象的生命周期。如果您将参数设置为非引用,那么它也可以,因为它将生成临时对象的本地副本。

答案 1 :(得分:2)

back()不返回迭代器。相反,它返回对向量的最后一个元素的引用。

答案 2 :(得分:1)

您正在执行对象的浅表副本,然后对副本进行排序。 back()返回对最后一个元素的引用,因此您将从该引用复制到调用者范围内的返回变量。

答案 3 :(得分:1)

您正在传递参考资料 - 因此您可以返回参考资料:

MyObject& best(vector<MyObject>& objects) {
    vector<MyObject>::iterator result = objects.begin();
    if(result == objects.end()) throw std::runtime_error("Empty");
    else {
        for(vector<MyObject>::iterator pos = std::next(result);
            pos != objects.end();
            ++pos)
        {
            // Might be ! compare_MyObject_func 
            if(compare_MyObject_func(*result, *pos)) result = pos;
        }
    }
    return *result;
}

如果您只对某个元素感兴趣,则无需对任何内容进行排序。

注意:查找某个元素的复杂度为O(n),而排序为O(n log(n))