2

printMessage で、インデックスを使用して定数クラスのベクトルにアクセスすると正常に動作しますが、反復子 (*itr) では動作しません。イテレータが constant_iterator として宣言されている場合、正常に動作します。

なんで?

どちらの場合も、ベクトルを変更せずにデータを読み取っています。誰かが光を当てることができますか?

 #include <iostream> 
 #include <vector>
 #include <sstream>

 //Set this define to enable the block to compile.
 #define WILL_WORK 1
 #define WILL_NOT_WORK !WILL_WORK

 class TestMessage
 {
 public:
  TestMessage(){};
  typedef std::vector<int>  TestVec;
  typedef std::vector<int>::iterator TestItr;
  //The const iterator will work
  //typedef std::vector<uint32_t>::const_iterator TestItr;
  typedef std::vector<int>::size_type TestSize;
  TestVec m_testVector;
 };


 void printMessage(const TestMessage & tmessage)
 {
  std::ostringstream asciiMessage;

  asciiMessage << tmessage.m_testVector.size() << ",";

 #if WILL_NOT_WORK

 //This will not work
 // MS Visual Studio
 // error C2440: 'initializing' : cannot convert from
 // 'std::_Vector_const_iterator<_Ty,_Alloc>' to
 //     'std::_Vector_iterator<_Ty,_Alloc>'
 // GCC 
 // error: conversion from
 // '__gnu_cxx::__normal_iterator<const int*,
 //                               std::vector<int, std::allocator<int> > >'
 // to non-scalar type
 // '__gnu_cxx::__normal_iterator<int*,
 //                               std::vector<int, std::allocator<int> > >'
 // requested

  for (TestMessage::TestItr itr = tmessage.m_testVector.begin();
       itr != tmessage.m_testVector.end();
       ++itr)
  {
   asciiMessage << *itr;
  }

 #endif 

 #if WILL_WORK

  // This will work
  for(TestMessage::TestSize index = 0;
      index < tmessage.m_testVector.size();
      ++index)
  {
   asciiMessage << tmessage.m_testVector[index] << ",";
  }

 #endif

  asciiMessage << std::endl;

  std::cout << asciiMessage.str();
 }

 int main()
 {
  TestMessage message;
  message.m_testVector.push_back(10);
  message.m_testVector.push_back(20);
  message.m_testVector.push_back(30);
  message.m_testVector.push_back(40);
  printMessage(message);
  return 0;
 }
4

4 に答える 4

4

2 つの異なる [] 演算子があります。1 つの定数、1 つの非定数。

const-[] 演算子は const-reference を返すため、インデックスの値は変更できません。

通常の反復子は非 const です。つまり、ベクターを変更できるとコンパイラが判断する可能性があります。結局のところ、反復子を関数に渡すことはできますが、呼び出された関数が反復子/ベクトルの内容を変更しないことをコンパイラが保証できる方法はありません。

したがって、const_iterator もあります。const_iterator を使用してベクター内の値を変更することはできません。これは、コンパイラによって直接チェックできます。const_iterator を関数に渡すと、コンパイラは、呼び出された関数が本来あるべき動作をする、つまり const_iterator が指している場所を変更しないと想定することしかできません。

于 2010-02-11T19:30:51.987 に答える
0

定数要素のベクトルに対する反復子 (const_iterator とは対照的に) は許可されていません。イテレータを使用すると、ベクター要素を変更したり、読み取ったりできます。コンパイラは、変更するかどうかを確認しません。イテレータの使用を完全に禁止するだけです。const_iterator を使用すると、const 要素を読み取ることができます。

于 2010-02-11T19:31:01.953 に答える
0

(非定数) イテレータ使用すると、そうしなくてもオブジェクトを変更できるためです。C++ の const 強制は純粋に型に基づいています。代わりに実行内容に基づいて強制するには、書き込み先を実行時に監視する必要があります。深刻なパフォーマンスの問題なしにそれを行うには、深刻なハードウェア サポートが必要です。

于 2010-02-11T19:31:29.053 に答える
0

TestMessageオブジェクトを への const 参照として渡していますprintMessage。そのため、このオブジェクト ベクトルを反復処理しようとすると、コンパイラはconst_iterator. これを非 const イテレータに変換することはできないため (これらのイテレータの基になる実装である を に自動的に変換することはできませんint*) const int*、コンパイルは失敗します。

ただし、ベクトルで使用すると、この演算子には定数を処理するためのオーバーロードされたバージョンがあるため、目的の位置にoperator[]ある an への const 参照が自動的に取得されます。int

の宣言printMessageを thisvoid printMessage(TestMessage & tmessage)に変更すると、コンパイルされます。ただし、印刷メッセージ関数は明らかに引数として渡されたオブジェクトを変更する意図がないため、const-correcteness が壊れてしまうため、これを行うべきではありません。TestMessage

于 2010-02-11T20:09:31.517 に答える