2000

Grusel++ of the month

Home
Download Source
/******************************************************************************/
/*                                                                            */
/*                                                         FILE: december.cpp */
/*                                                                            */
/*  Slowly, I begin to appreciate the STL                                     */
/*  =====================================                                     */
/*                                                                            */
/*  Compiled and tested with Visual C++ V6.0                                  */
/*                                                                            */
/*  V1.00   19-DEC-2000   P. Tellenbach   http://www.heimetli.ch/             */
/*                                                                            */
/******************************************************************************/

#include <iostream>
#include <algorithm>

class Process
{
 public:
   operator()( char ch )
   {
      std::cout.put( ch ) ;
   }

   operator int()
   {
      return 0 ;
   }
} ;

int main()
{
   char *ps = "Hello world !\n" ;

   return std::for_each( ps, std::find(ps,(char *)0,'\0'), Process() ) ;
}

Update 19. December 2020

The compiler complained about operator() without a return type. Declaring the method as void corrected the problem.

The warnings about const and non-const were also easy to fix.

But then the program printed a lot of nonsense and crashed!

This turned out to be a consequence of an optimization in the implementation of the find-algorithm in the library. The function checks the iterator-type and calls a different version for random access iterators. This version determines the distance between the iterators and tries to partially unroll the loop. The nullptr passed as end of the sequence produces a negative number and that produces an incorrect result.

This could be solved by adding a large number to the pointer, but I decided to use a custom iterator which identifies itself as an input-iterator.

/******************************************************************************/
/*                                                                            */
/*                                                         FILE: december.cpp */
/*                                                                            */
/*  Slowly, I begin to appreciate the STL                                     */
/*  =====================================                                     */
/*                                                                            */
/*  Compiled and tested with Visual C++ V6.0                                  */
/*                                                                            */
/*  V1.00   19-DEC-2000   P. Tellenbach   http://www.heimetli.ch/             */
/*                                                                            */
/*  Compiled and tested with g++ V8.3.0                                       */
/*                                                                            */
/*  V2.00   19-DEC-2020   P. Tellenbach   https://www.heimetli.ch/            */
/*                                                                            */
/******************************************************************************/

#include <iostream>
#include <algorithm>
#include <iterator>

class CharIterator : public std::iterator<std::input_iterator_tag, char>
{
  const char* ptr;
public:
  CharIterator( const char* p ) : ptr( p )
  {
  }

  CharIterator( const CharIterator &it ) : ptr( it.ptr )
  {
  }

  CharIterator& operator++()
  {
     ++ptr ;
     return *this ;
  }
  CharIterator operator++(int)
  {
     CharIterator tmp(*this) ;
     operator++() ;
     return tmp;
  }
  bool operator==(const CharIterator& rhs) const
  {
     return ptr == rhs.ptr ;
  }

  bool operator!=(const CharIterator& rhs) const
  {
     return ptr != rhs.ptr ;
  }

  const char& operator*()
  {
     return *ptr ;
  }
};

class Process
{
 public:
   void operator()( char ch )
   {
      std::cout.put( ch ) ;
   }

   operator int()
   {
      return 0 ;
   }
} ;

int main()
{
   const char *ps = "Hello world !\n" ;

   return std::for_each( CharIterator(ps), std::find(CharIterator(ps),CharIterator(nullptr),'\0'), Process() ) ;
}