【问题标题】:C++ returning reference from function with type of dereferenced type?C ++从具有取消引用类型的函数返回引用?
【发布时间】:2014-01-23 03:03:44
【问题描述】:

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

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>&);

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

【问题讨论】:

    标签: c++ reference iterator return


    【解决方案1】:

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

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

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

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


    除此之外,我建议也只按值取参数(删除&amp;):

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

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


    回答您的扩展问题:

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

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

    【讨论】:

    • 所以我应该添加MyObject bestObj = copy_objects.back();,然后添加return bestObj;,而不是我目前正在做什么?这会改变什么吗?
    • @synaptik 不,这不会改变任何事情。你只是介绍了一个额外的副本。返回对象的初始化方式与变量的初始化方式相同。
    • 好的。当然,我的术语不正确,但该功能应该像我解释的那样工作,我希望它工作。对吗?
    • @synaptik 查看我对参数类型的补充。
    • 这很有意义。因此,像您建议的那样,将 best 更改为使用按值传递,也可以解决 extension 问题。顺便说一句,你的答案清晰,值得表扬。非常感谢!
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 是的,我知道。我的问题是 return 语句中发生了什么。
      【解决方案4】:

      您正在传递一个引用 - 因此您可以返回一个引用:

      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))

      【讨论】:

      • 这是真的,但你可能想解释一下,你已经完全改变了他的算法,不涉及排序。
      猜你喜欢
      • 1970-01-01
      • 2018-12-08
      • 1970-01-01
      • 1970-01-01
      • 2012-10-28
      • 1970-01-01
      • 1970-01-01
      • 2017-06-18
      • 2016-08-17
      相关资源
      最近更新 更多