1

I'm writing an UTF-8 string class and it's two const and non-const iterator classes. I'm encountering a const problem. Here are the classes :

class Utf8String
{
public:

   class ConstIter;

   class Iter
   {
      friend class ConstIter;

   private:

      Iter();

   private:

      Utf8String * m_pStr;

      utf8::iterator< char * > m_oIter;

   public:

      Iter( const Iter & );

      inline explicit Iter( Utf8String * pStr )
       : m_pStr( pStr )
       , m_oIter( m_pStr->m_sBuf, m_pStr->m_sBuf, m_pStr->m_sBuf + m_pStr->m_nSize )
      { }

      inline Iter & operator = ( const Iter & oIter )
      {
         m_pStr = oIter.m_pStr;
         m_oIter = utf8::iterator< char * >(
            m_pStr->m_sBuf,
            m_pStr->m_sBuf,
            m_pStr->m_sBuf + m_pStr->m_nSize );

         return *this;
      }

      inline operator const char * () const
      {
         return m_oIter.base();
      }

      inline uchar32_t operator * () const
      {
         return *m_oIter;
      }

      inline Iter & operator ++ ()
      {
         ++m_oIter;
         return *this;
      }

      inline Iter & operator -- ()
      {
         --m_oIter;
         return *this;
      }

      inline bool operator == ( const Iter & oIter )
      {
         return m_oIter == oIter.m_oIter;
      }

      inline bool operator != ( const Iter & oIter )
      {
         return m_oIter != oIter.m_oIter;
      }
   };

   class ConstIter
   {
   private:

      ConstIter();

   private:

      const Utf8String * m_pStr;

      utf8::iterator< const char * > m_oIter;

   public:

      ConstIter( const ConstIter & );

      inline ConstIter( const Iter & oIter )
       : m_pStr( oIter.m_pStr )
       , m_oIter( m_pStr->m_sBuf, m_pStr->m_sBuf, m_pStr->m_sBuf + m_pStr->m_nSize )
      { }

      inline ConstIter( const Utf8String * pStr )
       : m_pStr( pStr )
       , m_oIter( m_pStr->m_sBuf, m_pStr->m_sBuf, m_pStr->m_sBuf + m_pStr->m_nSize )
      { }

      inline operator const char * () const
      {
         return m_oIter.base();
      }

      inline ConstIter & operator = ( const ConstIter & oIter )
      {
         m_pStr = oIter.m_pStr;
         m_oIter = utf8::iterator< const char * >(
            oIter.m_pStr->m_sBuf,
            oIter.m_pStr->m_sBuf,
            oIter.m_pStr->m_sBuf + oIter.m_pStr->m_nSize );

         return *this;
      }

      inline ConstIter & operator = ( const Iter & oIter )
      {
         m_pStr = oIter.m_pStr;
         m_oIter = utf8::iterator< const char * >(
            m_pStr->m_sBuf,
            m_pStr->m_sBuf,
            m_pStr->m_sBuf + m_pStr->m_nSize );

         return *this;
      }

      inline uchar32_t operator * () const
      {
         return *m_oIter;
      }

      inline ConstIter & operator ++ ()
      {
         ++m_oIter;
         return *this;
      }

      inline ConstIter & operator -- ()
      {
         --m_oIter;
         return *this;
      }

      inline bool operator == ( const ConstIter & oIter )
      {
         return m_oIter == oIter.m_oIter;
      }

      inline bool operator != ( const ConstIter & oIter )
      {
         return m_oIter != oIter.m_oIter;
      }
   };

   // More stuff
};

Which i'm using as follows :

   Utf8String sStr = "not const";

   for( Utf8String::Iter i = sStr.Begin(); i != sStr.End(); ++i )
   {
   }

   // 2) Iterating over a const UTF-8 string :

   const Utf8String sConstStr = "const";

   for( Utf8String::ConstIter i = sConstStr.Begin(); i != sConstStr.End(); ++i )
   {
   }

   // 3) Const interators can also iterate over a non-const string :

   for( Utf8String::ConstIter i = sStr.Begin(); i != sStr.End(); ++i )
   {
   }

The problem is that, if the copy constructor of the iterator classes are not declared public, i'm getting the following error, despite that copy constructor not being explicitly used :

Error   1   error C2248: 'core::Utf8String::Iter::Iter' : cannot access private member declared in class 'core::Utf8String::Iter'   c:\xxx\main.cpp 20

Declaring these copy constructors public solve the problem.

What happens ? Is the compiler optimizing Utf8String::ConstIter i = sStr.Begin() into Utf8String::ConstIter i( sStr.Begin() ) or doing some other implicit optimization ?

Thanks for your help. :)

EDIT: Using VS2005 and no C++11.

Virus721
  • 8,061
  • 12
  • 67
  • 123
  • 2
    `Utf8String::ConstIter i = sStr.Begin()` calls the copy constructor. What else would it call? – TartanLlama May 18 '15 at 08:15
  • I assumed it would call default constructor and then operator =. Why not ? – Virus721 May 18 '15 at 08:17
  • Nope, it's pretty much the same as the direct initialization that you compared to, except `explicit` constructors aren't considered. It's called [copy initialization](http://en.cppreference.com/w/cpp/language/copy_initialization). – TartanLlama May 18 '15 at 08:18
  • 1
    See [Is there a difference in C++ between copy initialization and direct initialization?](http://stackoverflow.com/questions/1051379/is-there-a-difference-in-c-between-copy-initialization-and-direct-initializati) – Daniel Daranas May 18 '15 at 08:19

1 Answers1

3

Utf8String::ConstIter i = sStr.Begin(); is a declaration together with an initialization. It is not an assignment. This initialization is done using the copy constructor.

TobiMcNamobi
  • 4,687
  • 3
  • 33
  • 52