On May 22, 2008, at 6:21 PM, Dale King wrote:

I'm going to file a bug on what I consider a major problem with wide
versus normal character strings and the << operator to append to the
MessageBuffer. The problem is that the first thing in your message
determines the behavior of the rest of the message.

That is by design.


If the first thing
you output is not a wide string, then any other character strings that
are wide will be treated as just the pointer value.

That is a side effect of the compiler casting the wchar_t* to int for us. If the L"2"



Consider these statements on a platform (i.e. Windows) where WCHAR is
used with various combinations of wide and normal strings:

   LOG4CXX_TRACE( logger, L"1" << L"2" );
   LOG4CXX_TRACE( logger, "1" << L"2" );
   LOG4CXX_TRACE( logger, L"1" << "2" );
   LOG4CXX_TRACE( logger, 1 << "2" );
   LOG4CXX_TRACE( logger, 1 << L"2" );

The expected result is 5 logging events all with the message "12".
Instead I get:

  12
  1006E1C4C
  12
  12
  1006E1C4C

Most of the << operators in the MessageBuffer class return either
CharMessageBuffer & or std::ostream &. I think all of these should
probably be returning MessageBuffer which would allow it to switch to
a WideMessageBuffer if I ever add a wide string, not just if the first
string is wide.


The idea of the whole MessageBuffer family was support for std::basic_string<char> insertion behavior that the log4cxx 0.9.7 offered while eliminating the surprisingly expensive (at least for some STL implementations) std::basic_ostream<char> constructor when you were just logging a single char* and working right when logging wchar_t strings. The last had more flexibility since there wasn't a released code base with which we had to be compatible. Getting that to work and working across multiple compilers was to say the least a challenge.

As far as I can tell, the behavior you are observing is the same as you would get with log4cxx 0.9.7, even if it was not what you would expect.

If instead of

   LOG4CXX_TRACE( logger, "1" << L"2" );

you had done

   LOG4CXX_TRACE( logger, "1" << std::wstring(L"2") );

you would have gotten a compile error (at least with gcc on Mac OS/ X). That is because the compiler won't quietly cast a std::wstring to an int like it does a wchar_t*. If the first works, then the second should also be supported.

Things would really start getting hugely complicated if you started inserting objects where one might only have a std::basic_ostream<char> insertion operator and another might only have a std::basic_ostream<wchar_t> operator. Then throw in manipulators and things just spiral out of control trying to do it perfect.

I'd be leaning toward adding private insertion operations to result in a compiler error when you mismatch string types on a logging call. That might result in some code that compiled in log4cxx 0.9.7 to fail to compile (code that expected the pointer value to be output), but that seems like an improvement to break that code.

Reply via email to