【问题标题】:Constant correctness恒定的正确性
【发布时间】:2011-01-15 20:50:08
【问题描述】:

在 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;
 }

【问题讨论】:

    标签: c++ vector iterator constants const-iterator


    【解决方案1】:

    有 2 个不同的 [] 运算符。一个常量,一个非常量。

    const-[] 运算符返回一个 const-reference,因此索引处的值不能更改。

    普通的迭代器是非常量的,这意味着编译器可能认为你可以改变向量。毕竟,您可以将迭代器传递给函数,然后编译器无法保证被调用的函数不会更改迭代器/向量的内容。

    因此,还有一个 const_iterator。 const_iterator 不能用于更改向量中的值。这可以由编译器直接检查。 如果将 const_iterator 传递给函数,编译器只能假定被调用函数的行为应如此,即不会更改 const_iterator 指向的位置。

    【讨论】:

      【解决方案2】:

      不允许在常量元素向量上使用迭代器(与 const_iterator 相对)。迭代器允许您修改向量元素以及读取它。编译器不会检查你是否修改它;它只是完全禁止使用迭代器。 const_iterator 允许您读取 const 元素。

      【讨论】:

        【解决方案3】:

        因为(非常量)迭代器允许您修改对象,即使您不这样做。 C++ 的 const 强制执行完全基于类型——要基于您所做的强制执行,它必须对您写入的内容进行运行时监控。在没有严重性能问题的情况下,需要严格的硬件支持才能做到这一点。

        【讨论】:

          【解决方案4】:

          您将TestMessage 对象作为对printMessage 的常量引用传递。因此,当您尝试迭代此对象向量时,编译器需要const_iterator。由于无法将其转换为非常量迭代器(无法将int* 自动转换为const int*,这些迭代器的底层实现),因此编译将失败。

          但是,当您将 operator[] 与向量一起使用时,您会自动在所需位置获得对 int 的 const 引用,因为该运算符具有处理常量的重载版本。

          如果您将printMessage 的声明更改为此void printMessage(TestMessage &amp; tmessage),它将编译。但是您应该这样做,因为您会破坏 const-correcteness,因为您的打印消息函数显然无意修改作为参数传递的 TestMessage 对象。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2021-07-30
            • 2017-07-16
            • 2020-09-02
            • 1970-01-01
            • 1970-01-01
            • 2016-07-18
            • 1970-01-01
            相关资源
            最近更新 更多