返回 C++ 迭代器引用

Posted

技术标签:

【中文标题】返回 C++ 迭代器引用【英文标题】:Return C++ iterator reference 【发布时间】:2014-12-05 11:32:57 【问题描述】:

按预期工作的示例

#include <iostream>
#include <vector>

struct MyClass


  const std::vector<float>::iterator& begin()
    return myvec.begin();
  

  const std::vector<float>::iterator& end()
    return myvec.end();
  
  std::vector<float> myvec;
;

int main()

  std::vector<float> mainvec(8,0);

  MyClass myClass;

  myClass.myvec = mainvec;

  for (std::vector<float>::iterator it = myClass.begin();
      it != myClass.end();++it)
    std::cout << *it << " " ;
  

  std::cout << std::endl;

在这段代码中,我得到以下输出:

0 0 0 0 0 0 0 0 

一个没有按预期工作的例子:

#include <iostream>
#include <vector>

struct MyClass


  const std::vector<float>::iterator& begin()
    return myvec.begin();
  

  const std::vector<float>::iterator& end()
    return myvec.end();
  
  std::vector<float> myvec;
;

int main()

  std::vector<float> mainvec(8,0);

  MyClass myClass;

  myClass.myvec = mainvec;

  const std::vector<float>::iterator& end_reference = myClass.end();

  for (std::vector<float>::iterator it = myClass.begin();
      it != end_reference;++it)
    std::cout << *it << " " ;
  

  std::cout << std::endl;

在这段代码中,我得到以下输出:

"empty output"

第一个代码示例

问题在于我调用(错误地)向量 begin()end() 而不是 MyClass 方法。

我有以下最少的代码来表示我的疑问:

#include <iostream>
#include <vector>

struct MyClass


  const std::vector<float>::iterator& begin()
    return myvec.begin();
  

  const std::vector<float>::iterator& end()
    return myvec.end();
  
  std::vector<float> myvec;
;

int main()

  std::vector<float> mainvec(8,0);

  MyClass myClass;

  myClass.myvec = mainvec;

  for (std::vector<float>::iterator it = myClass.myvec.begin();
      it != myClass.myvec.end();++it)
    std::cout << *it << " " ;
  

  std::cout << std::endl;

我在第 8 行和第 12 行收到以下警告:

returning reference to local temporary object [-Wreturn-stack-address] [cpp/gcc] 

但是当我编译并运行程序时,我得到:

0 0 0 0 0 0 0 0 

所以,似乎本地引用在返回myvec.begin() 时没有被破坏。当我第一次编写代码时,我并不认为这会是一个问题,因为在我的脑海中,来自向量的 begin() 方法将返回一个指向第一个向量位置的迭代器引用,这个迭代器对我来说不是当我执行 myvec.begin() 时分配,但它是对这个迭代器的引用。所以,这个警告不应该出现,因为我没有分配内存。但是由于我不知道这种机制是如何工作的,所以我想学习它以编写一致的代码。看来我可以忽略这个警告,不是吗?

【问题讨论】:

你从哪里得知begin() 返回一个引用? 您在the description of std::vector::begin() 的哪个位置看到任何提及参考结果的内容?它返回一个对象 @Werner:您想知道为什么未定义的行为不会给出明确定义的行为?因为它是未定义的。 (在这种情况下,它可能只是意味着被破坏对象的存储在被复制到局部变量之前没有被重用,所以它仍然包含旧值。但你不能依赖这种行为。)跨度> @Werner:确实,在对象的生命周期结束后使用对象总是 UB,返回对自动变量或临时变量的引用总是错误的。一旦程序的生命周期结束,就没有(便携式)方法可以阻止程序重用其内存。您需要按值返回迭代器。 仅供参考,您的实际调用代码是有效的,因为您从不调用您的 begin() end() 成员 MyClass。相反,您直接调用myClass.myvec.begin()myClass.myvec.end()。您的 Ub 蓬勃发展的成员未被召唤。 【参考方案1】:

std::vector::begin 确实返回一个临时对象 (见http://www.cplusplus.com/reference/vector/vector/begin/)

您的代码是有效的,因为您将临时对象绑定到 const 引用(使用非 const 引用是不合法的),并立即将其复制到局部变量 it 编辑:我的错误。这确实也是 UB 从一个临时返回一个 const 引用。

但是,将此引用分配给另一个具有更长生命周期的 const 引用会导致未定义的行为,因为临时对象的生命周期只会延长到直接分配给它的 const 引用的生命周期。

我建议考虑警告并返回一个迭代器。

我也推荐阅读http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/

【讨论】:

我会阅读推荐的!这似乎正是我需要的补充。但是,我仍然觉得 const 引用(即使临时对象的跨度时间有限)正是示例中所需要的…… 我不认为这是正确的。 const 引用必须至少在与临时引用相同的范围内(并且在 Herb 表示其有效的所有链接文章示例中都是如此)。这里情况不同。一旦被调用的函数返回,临时的绝对gone。可以肯定的是,标准的§12.2/5 [class.temporary] 描述了这一点,尽管不是最简单的术语。如果这不是一个准确的评估,那么我通过 const-reference 了解的关于临时生命周期延长的所有知识都被淘汰了。 加上第三段,这似乎是正确的。因此+1。

以上是关于返回 C++ 迭代器引用的主要内容,如果未能解决你的问题,请参考以下文章

如何正确地从 C++ 中的迭代器返回对对象的引用

通过引用传递 C++ 迭代器有啥问题?

向量迭代器不可取消引用 C++

C++ STL list迭代器

这段代码在哪里取消引用无效的迭代器? (C++)

返回 c++ 迭代器