如果容器元素是指针,为什么我允许从const_iterator调用非const成员函数?

时间:2012-06-09 23:02:17

标签: c++ iterator const

请考虑以下代码:

#include <vector>
using namespace std;

struct foo
{
  void bar()
  {
  }
};

int main()
{
  {
    vector<foo*> a;
    a.push_back(new foo());
    a.push_back(new foo());
    a.push_back(new foo());

    vector<foo*>::const_iterator itr = a.begin();
    (*itr)->bar(); // compiles - this becomes more confusing 
                   // when found in a const method. On first 
                   // glance, one will (or at least me) may
                   // assume that bar() must be const if the 
                   // method where it is being called from is 
                   // const

    // The above compiles because internally, this is what happens 
    // (ignore the fact that the pointer has not been newd)
    foo* const * element;
    (*element)->bar(); // compiles

    // What I would expect however (maybe it is just me) is for const_iterator
    // to  behave something like this
    const foo* const_element;
    const_element->bar(); // compile error
  }

  {
    vector<foo> a;
    a.resize(10);

    vector<foo>::const_iterator itr = a.begin();
    itr->bar(); // compile error
  }

}

我理解为什么可以调用它。 const_iterator存储这样的常量:const T*,指针转换为foo* const *,对象转换为foo const *

所以我的问题是,为什么我们允许从const_iterator调用非const成员函数?不允许从const_iterator调用非const成员函数更直观吗?使用const选项设计iterator s不应该阻止这种行为吗?

现在更重要的问题是:如果我希望const_iterator禁止调用指向对象的非const成员函数怎么办?

3 个答案:

答案 0 :(得分:5)

  

使用const选项设计迭代器不应该阻止这种行为吗?

确实如此。您只是希望它是不同的操作。

正如您所发现的,指针容器......包含指针,而不是对象。因此,const_iterator这样的指针意味着指针是常量,而不是它们指向的对象。

这不会改变,也不会改变。标准库容器通常设计为包含完整的对象,而不是指针。所以他们不应该鼓励用户制作vector指针和其他可疑的结构。

如果您确实需要vector来包含指针,那么您应该使用实际上设计的容器来执行此操作。像Boost's pointer container classes一样。他们的const_iterators使对象正确指向const。他们还做其他有用的事情,比如拥有他们指向的对象(以便正确删除它们)等等。

答案 1 :(得分:2)

你有一个指针向量,指针不具有成员函数,所以你不会在存储在向量中的东西上调用成员函数。

取消引用指针时获得的对象类型取决于该指针的类型。你的向量是非常量指针的向量,所以当你从容器中解除任何指针时,你总是得到一个指向对象的非常量引用。

如果你想要一个指针矢量,那么你有两个选择。你可以创建一个vector<const foo*>而你将永远无法检索对任何指向对象的指针的非const引用,或者,如果你需要能够从向量的非const实例获取非const引用您必须创建一个包含向量作为私有成员变量的对象,并通过传递接口为您提供所需的访问权限。

如果你的向量应该拥有它拥有指针的对象,你可以考虑简单vector<foo>,或者如果需要动态分配,可以考虑boost::ptr_vector<foo>

答案 2 :(得分:1)

  

所以我的问题是,为什么我们允许从const_iterator调用非const成员函数?

“常量迭代器”表示容器元素是常量。这并不意味着如果该元素是指针,则指向的对象也是常量。

  

如果我希望const_iterator禁止调用指向对象的非const成员函数,该怎么办?

我不想鼓励你使用像这样的原始指针,但是如果你真的需要,那就把它作为指向const对象的指针的容器。

std::vector<const foo*> a;
// ...
auto itr = a.cbegin();
(*itr)->bar(); // Compiler error (calling a non-const method on const object).

当然,在这种情况下,以下情况也是不允许的:

std::vector<const foo*> a;
// ...
auto itr = a.begin();
(*itr)->bar(); // Compiler error.