Search code examples
c++coutnull-pointer

teach cout to handle null pointers gracefully


In my program I handle c style strings (of type char *) that are somtimes NULL. I would like to teach cout to handle those gracefully (i.e. to print "(null)" instead of segfaulting).

My first attempt:

ostream& operator<< (ostream &out, const char *p_str) {
    if (p_str == nullptr)
        out << "(null)";
    else
        out << p_str;
    return out;
}

Does not work because it leads to an infinite recursion (in both if and else clause). Two questions:

  1. I can break the infinite recursion by calling the original operator<< from my redefined version. How do I do this? (lacking C++ skills here...)
  2. Is there a better (more idiomatic) way to achieve what I want?

Solution

  • The original output operators for strings are non-members defined in namespace std as

    namespace std {
      template< class CharT, class Traits >
      basic_ostream<CharT,Traits>& operator<<(basic_ostream<CharT,Traits>&, const CharT*);
    
      template< class CharT, class Traits >
      basic_ostream<CharT,Traits>& operator<<(basic_ostream<CharT,Traits>&, const char*);
    
      template< class Traits> 
      basic_ostream<char,Traits>& operator<<(basic_ostream<char,Traits>&, const char*);
    
      template< class Traits >
      basic_ostream<char,Traits>& operator<<(basic_ostream<char,Traits>&, const signed char*);
    
      template< class Traits >
      basic_ostream<char,Traits>& operator<<(basic_ostream<char,Traits>&, const unsigned char*);
    }
    

    and are found by ADL. But you can, of course, call them explicitly as in (recall that std::ostream is merely a typedef to std::basic_ostream<char,std::char_traits<char>>)

    inline std::ostream& operator<< (std::ostream &out, const char *p_str)
    {  
      return std::operator<< (out, p_str==nullptr? "(null)" : p_str);
    }
    

    Overloading these operators in the global namespace is possible (though I'm not sure this is allowed by the standard), though I'd do this inside the namespace from which you're using them.