Постоянная корректность - PullRequest
2 голосов
/ 11 февраля 2010

В 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 голосов
/ 11 февраля 2010

Есть 2 разных оператора []. Один const, один не const.

Оператор const- [] возвращает const-ссылку, и поэтому значение в индексе нельзя изменить.

Обычный итератор неконстантный, это означает, что компилятор может подумать, что вы можете изменить вектор. В конце концов, вы можете передать итератор в функцию, и тогда компилятор не сможет гарантировать, что вызываемая функция не изменит содержимое итератора / вектора.

Следовательно, существует также const_iterator. Const_iterator нельзя использовать для изменения значений в векторе. Это может быть проверено непосредственно компилятором. Если вы передадите const_iterator функции, компилятор может только предполагать, что вызываемая функция ведет себя так, как и должно быть, а именно, не изменяя то, на что указывает const_iterator.

0 голосов
/ 11 февраля 2010

Вы передаете свой объект TestMessage как постоянную ссылку на printMessage. Из-за этого, когда вы пытаетесь перебрать этот объектный вектор, компилятор ожидает const_iterator. Поскольку невозможно преобразовать его в неконстантный итератор (невозможно автоматически преобразовать int* в const int*, базовую реализацию этих итераторов), компиляция завершится неудачно.

Однако, когда вы используете operator[] с вектором, вы автоматически получаете константную ссылку на int в нужной позиции, учитывая, что этот оператор имеет перегруженную версию для работы с константами.

Если вы измените свое объявление printMessage на это void printMessage(TestMessage & tmessage), оно будет скомпилировано. Но вы должны , а не сделать это, поскольку вы нарушите const-correcteness, так как ваша функция печати сообщения явно не намерена изменять объект TestMessage, переданный в качестве аргумента.

0 голосов
/ 11 февраля 2010

Поскольку (неконстантный) итератор будет позволять вам изменять объект, даже если вы этого не делаете. В C ++ принудительное применение const основано исключительно на типах - для принудительного применения в зависимости от того, что вы делаете вместо этого, он должен иметь мониторинг во время выполнения того, что вы написали. Для этого потребуется серьезная аппаратная поддержка без серьезных проблем с производительностью.

0 голосов
/ 11 февраля 2010

Итератор (в отличие от const_iterator) для вектора постоянных элементов недопустим. Итератор позволяет изменять элемент вектора, а также читать его. Компилятор не проверяет, изменили ли вы do ; он просто запрещает использовать итератор вообще. Const_iterator позволяет читать элементы const.

...