4

次のコードを検討してください。

#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_iteratorconst-ness を次のように格納します。const T*これは、ポインタfoo* const *の場合は および オブジェクトの場合に変換されますfoo const *

だから私の質問は、なぜ const 以外のメンバー関数を a から呼び出すことができるのconst_iteratorですか? からの非 const メンバー関数の呼び出しを許可しない方が直感的ではありませんconst_iteratorか? iteratorconst オプションを使用した sの設計は、この動作を防ぐべきではありませんか?

より重要な問題は次のとおりです。ポイント先のオブジェクトの非 const メンバー関数の呼び出しを禁止したい場合はどうすればよいでしょうか?const_iterator

4

3 に答える 3

5

const オプションを使用したイテレータの設計は、この動作を防ぐべきではありませんか?

します。あなたはそれがの操作であることを期待しているだけです。

あなたが発見したように、ポインターのコンテナーには、オブジェクトではなくポインターが含まれています。したがって、そのconst_iteratorようなポインターへの a は、ポインターが指すオブジェクトではなく、ポインターが定数であることを意味します。

それは変わらないし、変わるべきでもない。標準ライブラリ コンテナーは、通常、ポインターではなく、本格的なオブジェクトを格納するように設計されています。したがって、ユーザーにvectorポインターやその他の疑わしい構造を作成するように勧めるべきではありません。

ポインターを格納する必要がある場合は、実際にそのように設計されvectorたコンテナーを使用する必要があります。Boost のポインタ コンテナ クラスのように。それらは、オブジェクトが適切に指されているようにします。また、指し示すオブジェクトを所有する (適切に削除されるようにする) など、他の便利なことも行います。const_iteratorsconst

于 2012-06-09T23:11:23.853 に答える
2

ポインターのベクトルがあり、ポインターにはメンバー関数がないため、ベクトルに格納されているものに対してメンバー関数を呼び出していません。

ポインターを逆参照するときに取得するオブジェクトの型は、そのポインターの型によって異なります。ベクターは非定数ポインターのベクターであるため、コンテナーからポインターを逆参照すると、常に、指定されたオブジェクトへの非定数参照が取得されます。

ポインターのベクトルが必要な場合は、2 つのオプションがあります。代わりにa を作成できます。vector<const foo*>オブジェクトへのポインターへの非 const 参照を取得することはできません。または、ベクトルの非 const インスタンスから非 const 参照を取得できるようにする必要がある場合は、作成する必要があります。ベクトルをプライベート メンバー変数として含み、パススルー インターフェイスを介して必要なアクセスを提供するオブジェクト。

ベクターがポインターを保持するオブジェクトを所有することになっている場合は、代わりにシンプルと見なすことができます。vector<foo>動的割り当てが必要な場合は、boost::ptr_vector<foo>.

于 2012-06-09T23:12:35.537 に答える
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.
于 2012-06-09T23:29:33.340 に答える