【问题标题】:Returning iterator from constant member function从常量成员函数返回迭代器
【发布时间】:2015-06-01 21:13:27
【问题描述】:

在下面的代码中,为什么foo::func 的返回类型是vector<int>::const_iterator 而不是vector<int>::iterator,尽管我返回的是vector<int>::iterator 的对象。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class foo
{
private:
  vector<int> ar;
public:
  foo()
  {
    ar.resize(10);
    iota(ar.begin(), ar.end(), 1);
  }
  auto func() const
  {
    return ar.begin() + 5;
  }
};

int main()
{
  foo x;
  cout<<boolalpha<<endl;
  auto it = x.func();
  cout<<is_same<decltype(it), vector<int>::iterator>::value<<endl;
  cout<<is_same<decltype(it), vector<int>::const_iterator>::value<<endl;
  return 0;
}

以上代码的输出是:

false
true

如果我将foo::func() 重新定义为

auto func()
{
    return ar.begin() + 5;
}

输出将是

true
false

为什么常量成员函数将返回类型更改为常量? 我是否需要删除 const 关键字以使返回类型为 vector&lt;int&gt;::iterator 还是有其他方法?

【问题讨论】:

  • arconst vector&lt;int&gt;auto func() const 类型的左值。
  • const_iterator begin() const;在访问向量arconst时被调用,这是因为func() const说是。

标签: c++ c++11 g++ c++14


【解决方案1】:

声明为const 的成员函数会影响this 指针的类型。在func() 内,this 的类型为const foo*。因此,通过constthis 指针访问的所有成员类型本身将是const,因此ar 的隐式类型实际上是const std::vector&lt;int&gt;。在vector 的两个begin() 重载中,唯一可行的重载是const 重载,它返回const_iterator

当你把func()重新定义为非const,那么this的类型就是foo*,所以ar的类型就是std::vector&lt;int&gt;begin()的重载首选返回iterator

【讨论】:

    【解决方案2】:

    There are two std::vector::begin 取决于实例是否为const

    foo::func() const 中,您尝试访问ar,然后将其视为const std::vector&lt;int&gt;,而std::vector::begin() const 返回const_iterator

    当您在foo::func() 中访问ar 时,它会被视为std::vector&lt;int&gt;,没有const,然后begin 将引用std::vector::begin()(再次没有const),即功能不一样。

    同样,您自己的foo 类可以同时定义两个版本的foo::func

    auto func()
    { return ar.begin() + 5; }
    
    auto func() const
    { return ar.begin() + 5; }
    

    实例的常量将决定调用哪个版本:

    foo x;
    const foo y;
    
    x.func();    // First version, get an iterator
    y.func();    // Second version, get a const_iterator
    

    【讨论】:

      【解决方案3】:

      iterator 指向它的一个数据成员,因此如果函数是 const,那么 iterator 也必须是 const,否则您可以将 class 中包含的数据从 @987654326 更改@ 由 const 成员函数返回。

      至少这是我的理解 - 如果其他人能证实或否认这一点,我将不胜感激。

      【讨论】:

      • 可以发明一个容器,使一个 const 实例返回一个迭代器,它可以改变容器的元素。这两种情况之间的区别是通过一些约定。标准库容器类遵循称为 值语义 的约定,这意味着将容器视为其元素的序列。根据此约定,如果元素被修改,则容器被视为已修改。因此,StdLib 容器仅从 const 成员函数公开 const 迭代器。
      【解决方案4】:

      成员函数begin通过以下方式重载

      iterator begin() noexcept;
      const_iterator begin() const noexcept;
      

      因此,使用限定符 const 声明的函数处理常量对象。这意味着如果常量对象的数据成员未声明为mutable,它们也是常量。在这种情况下,为返回 const_iterator 的数据成员 ar 调用第二个重载函数 begin

      【讨论】:

        猜你喜欢
        • 2019-09-03
        • 2021-08-10
        • 2017-01-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多