【问题标题】:Why am I allowed to call a non-const member function from a const_iterator if the container element is a pointer?如果容器元素是指针,为什么我可以从 const_iterator 调用非常量成员函数?
【发布时间】:2012-06-09 23:02:16
【问题描述】:

考虑以下代码:

#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_iterator 调用非常量成员函数不是更直观吗?带有 const 选项的 iterators 的设计不应该防止这种行为吗?

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

【问题讨论】:

    标签: c++ iterator constants


    【解决方案1】:

    带有 const 选项的迭代器设计不应该防止这种行为吗?

    确实如此。你只是期望它是一个不同的操作。

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

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

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

    【讨论】:

      【解决方案2】:

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

      取消引用指针时获得的对象类型取决于该指针的类型。您的向量是非常量指针的向量,因此当您从容器中取消引用任何指针时,您始终会获得对指向对象的非常量引用。

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

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

      【讨论】:

        【解决方案3】:

        所以我的问题是,为什么我们可以从 const_iterator 调用非常量成员函数?

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

        如果我想让 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.
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-02-12
          • 1970-01-01
          • 2018-06-25
          • 2016-08-17
          • 1970-01-01
          • 2012-12-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多