Libstdc++-porting-howto
Felix Natter
Legal Notice
	This document can be distributed under the FDL
	(
http://www.gnu.orgwww.gnu.org )
      
Tue Jun  5 20:07:49 2001
Revision History Revision 0.5 Thu Jun  1 13:06:50 2000 fnatter First docbook-version. Revision 0.8 Sun Jul 30 20:28:40 2000 fnatter First released version using docbook-xml
	  + second upload to libstdc++-page.
	
Revision 0.9 Wed Sep  6 02:59:32 2000 fnatter 5 new sections. Revision 0.9.1 Sat Sep 23 14:20:15 2000 fnatter added information about why file-descriptors are not in the
	  standard
Revision 0.9.2 Tue Jun  5 20:07:49 2001 fnatter 	  a fix, added hint on increased portability of C-shadow-headers,
	  added autoconf-test HAVE_CONTAINER_AT
	
Revision 0.9.3 Fri Jun 29 16:15:56 2001 fnatter 	  changed signature of nonstandard filebuf-constructor and
	  update the section on filebuf::attach to point to ../ext/howto.html,
	  added link to ../21/strings/howto.html
	  in sec-stringstream, changed <link>-tags to have content
	  (so that these links work),
	  replace "user-space" by "global namespace"
	  add note about gcc 3.0 and shadow-headers			
	  add section about ostream::form and istream::scan
	  sec-vector-at: remove hint to modify headers
	  fix spelling error in sec-stringstream
	
Revision 0.9.4 Mon Nov  5 17:01:04 2001 fnatter 	  rewrite section 1.1.3 because of gnu.gcc.help-post by
	  Juergen Heinzl
	
Abstract
	Some notes on porting applications from libstdc++-2.90 (or earlier
	versions) to libstdc++-v3. Not speaking in terms of the GNU libstdc++
	implementations, this means porting from earlier versions of the
	C++-Standard to ISO 14882.
      
Table of Contents
1. #sec-nsstdNamespace std:: 1.1.1. #sec-gtkmm-hackUsing namespace
	  composition if the project uses a separate
	namespace
1.1.2. #sec-emptynsDefining an empty namespace std 1.1.3. #sec-avoidfqnAvoid to use fully qualified names
	(i.e. std::string)
1.1.4. #sec-osprojectsHow some open-source-projects deal
	with this
2. #sec-nocreatethere is no ios::nocreate/ios::noreplace
      in ISO 14882
3. #sec-stream::attachstream::attach(int
	fd) is not in the standard any more
4. #sec-headersThe new headers 4.4.1. #sec-cheadersNew headers replacing C-headers 4.4.2. #sec-fstream-header	<fstream> does
	not define std::cout,
	std::cin etc.
5. #sec-iteratorsIterators 6. #sec-macros      Libc-macros (i.e. isspace from
      <cctype>)
7. #sec-stream-stateState of streams 8. #sec-vector-atvector::at is missing (i.e. gcc 2.95.x) 9. #sec-eofUsing std::char_traits<char>::eof() 10. #sec-string-clearUsing string::clear()/string::erase() 11. #sec-scan-formGNU Extensions ostream::form and istream::scan 12. #sec-stringstreamUsing stringstreams 13. #sec-aboutAbout...     In the following, when I say portable, I will refer to "portable among ISO
    14882-implementations". On the other hand, if I say "backportable" or
    "conservative", I am talking about "compiles with older
    libstdc++-implementations".
  
Namespace std::
      The latest C++-standard (ISO-14882) requires that the standard
      C++-library is defined in namespace std::. Thus, in order to use
      classes from the standard C++-library, you can do one of three
      things:
      
wrap your code in namespace std {
	      ... }
 => This is not an option because only symbols
	    from the standard c++-library are defined in namespace std::.
	  
put a kind of
	    
using-declaration in your source (either
	    
using namespace std; or i.e. using
	      std::string;
) => works well for source-files, but
	    cannot be used in header-files.
	  
use a fully qualified name for
	    each libstdc++-symbol (i.e. 
std::string,
	    
std::cout) => can always be used
	  
    
      Because there are many compilers which still use an implementation
      that does not have the standard C++-library in namespace
      
std::, some care is required to support these as
      well.
    
      Namespace back-portability-issues are generally not a problem with
      g++, because versions of g++ that do not have libstdc++ in
      
std:: use -fno-honor-std      (ignore 
std::, :: = std::) by
      default. That is, the responsibility for enabling or disabling
      
std:: is on the user; the maintainer does not have
      to care about it. This probably applies to some other compilers as
      well.
    
      The following sections list some possible solutions to support compilers
      that cannot ignore std::.
    
Using namespace
	  composition
 if the project uses a separate
	namespace
	
http://gtkmm.sourceforge.netGtk--  defines
	most of its classes in namespace Gtk::. Thus, it was possible to
	adapt Gtk-- to namespace std:: by using a C++-feature called
	
namespace composition. This is what happens if
	you put a 
using-declaration into a
	namespace-definition: the imported symbol(s) gets imported into the
	currently active namespace(s). For example:
	
	  namespace Gtk {
	  using std::string;
	  class Window { ... }
	  }
	
	In this example, 
std::string gets imported into
	namespace Gtk::.  The result is that you don't have to use
	
std::string in this header, but still
	
std::string does not get imported into
	the global namespace (::) unless the user does
	
using namespace Gtk; (which is not recommended
	practice for Gtk--, so it is not a problem).  Additionally, the
	
using-declarations are wrapped in macros that
	are set based on autoconf-tests to either "" or i.e. 
using
	  std::string;
 (depending on whether the system has
	libstdc++ in 
std:: or not).  (ideas from
	
< mailto:llewelly@dbritsch.dsl.xmission.comllewelly@dbritsch.dsl.xmission.com >, Karl Nelson
	
< mailto:kenelson@ece.ucdavis.edukenelson@ece.ucdavis.edu >)
      
Defining an empty namespace std
	By defining an (empty) namespace 
std:: before
	using it, you avoid getting errors on systems where no part of the
	library is in namespace std:
	
	  namespace std { }
	  using namespace std;
	
      
Avoid to use fully qualified names
	(i.e. std::string)
	If some compilers complain about 
using
	  std::string;
, and if the "hack" for gtk-- mentioned above
	does not work, then I see two solutions:
	
	
	      Define 
std:: as a macro if the compiler
	      doesn't know about 
std::.
	      
		#ifdef OLD_COMPILER
		#define std
		#endif
	      
	      (thanks to Juergen Heinzl who posted this solution on
	      gnu.gcc.help)
	    
	      Define a macro NS_STD, which is defined to
	      either "" or "std"
	      based on an autoconf-test. Then you should be able to use
	      
NS_STD::string, which will evaluate to
	      
::string ("string in the global namespace") on
	      systems that do not put string in std::.  (This is untested)
	    
	  
      
How some open-source-projects deal
	with this
	This information was gathered around May 2000. It may not be correct
	by the time you read this.
      
Table 1. Namespace std:: in Open-Source programs
http://www.clanlib.orgclanlib usual http://pingus.seul.orgpingus usual http://www.mozilla.orgmozilla usual http://libsigc.sourceforge.net		  libsigc++
conservative-impl Table 2. Notations for categories
usual mostly fully qualified names and some
		using-declarations (but not in headers)
none no namespace std at all conservative-impl wrap all
		namespace-handling in macros to support compilers without
		namespace-support (no libstdc++ used in headers)
	As you can see, this currently lacks an example of a project
	which uses libstdc++-symbols in headers in a back-portable way
	(except for Gtk--: see the 
#sec-gtkmm-hacksection on the gtkmm-hack ).
      
there is no ios::nocreate/ios::noreplace
      in ISO 14882
      I have seen 
ios::nocreate being used for
      input-streams, most probably because the author thought it would be
      more correct to specify nocreate "explicitly".  So you can simply
      leave it out for input-streams.
    
      For output streams, "nocreate" is probably the default, unless you
      specify 
std::ios::trunc ? To be safe, you can open
      the file for reading, check if it has been opened, and then decide
      whether you want to create/replace or not. To my knowledge, even
      older implementations support 
app,
      
ate and trunc (except for
      
app ?).
    
stream::attach(int
	fd)
 is not in the standard any more
      Phil Edwards 
< mailto:pedwards@disaster.jaj.compedwards@disaster.jaj.com > writes:
      It was considered and rejected.  Not all environments use file
      descriptors.  Of those that do, not all of them use integers to represent
      them.
    
      When using libstdc++-v3, you can use
      
	  #include <fstream>
	
	    
basic_filebuf<...>::basic_filebuf<...>
	    
	  
(file, mode, size);__c_file_type* file;ios_base::open_mode mode;int size;
      but the the signature of this constructor has changed often, and
      it might change again. For the current state of this, check
      
../ext/howto.htmlthe howto for extensions .
    
      For a portable solution (among systems which use
      filedescriptors), you need to implement a subclass of
      
std::streambuf (or
      
std::basic_streambuf<..>) which opens a file
      given a descriptor, and then pass an instance of this to the
      stream-constructor.  For an example of this, refer to
      
http://www.josuttis.com/cppcode/fdstream.htmlfdstream example  
      by Nicolai Josuttis.
    
The new headers
      All new headers can be seen in this 
headers_cc.txt	source-code
.
    
      The old C++-headers (iostream.h etc.) are available, but gcc generates
      a warning that you are using deprecated headers.
    
New headers replacing C-headers
	You should not use the C-headers (except for system-level
	headers) from C++ programs. Instead, you should use a set of
	headers that are named by prepending 'c' and, as usual,
	omitting the extension (.h). For example, instead of using
	
<math.h>, you
	should use 
<cmath>. In some cases this has
	the advantage that the C++-header is more standardized than
	the C-header (i.e. 
<ctime> (almost)
	corresponds to either 
<time.h> or <sys/time.h>).
	The standard specifies that if you include the C-style header
	(
<math.h> in
	this case), the symbols will be available both in the global
	namespace and in namespace 
std:: (but
	libstdc++ does not yet have fully compliant headers) On the
	other hand, if you include only the new header (i.e. 
<cmath>), the symbols
	will only be defined in namespace 
std::	(and macros will be converted to inline-functions).
      
	For more information on this, and for information on how the
	GNU C++ implementation might reuse ("shadow") the C
	library-functions, have a look at 
http://www.cantrip.org/cheaders.html	  www.cantrip.org
.
      
	
<fstream> does
	not define 
std::cout,
	
std::cin etc.
	In earlier versions of the standard,
	
<fstream.h>,
	
<ostream.h>	and 
<istream.h>	used to define
	
cout, cin and so on. Because
	of the templatized iostreams in libstdc++-v3, you need to include
	
<iostream>	explicitly to define these.
      
Iterators
      The following are not proper uses of iterators, but may be working
      fixes for existing uses of iterators.
      
you cannot do
	    
ostream::operator<<(iterator) to
	    print the address of the iterator => use
	    
operator<< &*iterator instead ?
	  
you cannot clear an iterator's reference
	    (
iterator = 0) => use
	    
iterator = iterator_type(); ?
	  
if (iterator) won't work any
	    more => use 
if (iterator != iterator_type())	    ?
    
      Libc-macros (i.e. 
isspace from
      
<cctype>)
      Glibc 2.0.x and 2.1.x define the
      
<ctype.h>      -functionality as macros (isspace, isalpha etc.). Libstdc++-v3
      "shadows" these macros as described in the 
#sec-cheaderssection about
	c-headers
.
    
      Older implementations of libstdc++ (g++-2 for egcs 1.x and g++-3
      for gcc 2.95.x), however, keep these functions as macros, and so it
      is not back-portable to use fully qualified names. For example:
      
	#include <cctype>
	int main() { std::isspace('X'); }
      
      will result in something like this (unless using g++-v3):
      
	std:: (__ctype_b[(int) ( ( 'X' ) )] & (unsigned short int)
	_ISspace )  ;
      
    
      One solution I can think of is to test for -v3 using
      autoconf-macros, and define macros for each of the C-functions
      (maybe that is possible with one "wrapper" macro as well ?).
    
      Another solution which would fix g++ is to tell the user to modify a
      header-file so that g++-2 (egcs 1.x) and g++-3 (gcc 2.95.x) define a
      macro which tells 
<ctype.h> to define functions
      instead of macros:
      
	// This keeps isalnum, et al from being propagated as macros.
	#if __linux__
	#define __NO_CTYPE 1
	#endif
	[ now include <ctype.h> ]
      
    
      Another problem arises if you put a 
using namespace
	std;
 declaration at the top, and include <ctype.h>. This will result in
      ambiguities between the definitions in the global namespace
      (
<ctype.h>) and the
      definitions in namespace 
std::      (
<cctype>).
    
      The solution to this problem was posted to the libstdc++-v3
      mailing-list:
      Benjamin Kosnik 
< mailto:bkoz@redhat.combkoz@redhat.com > writes:
      &##x2018;
	--enable-cshadow-headers is currently broken. As a result, shadow
	headers are not being searched....
      &##x2019;
      This is now outdated, but gcc 3.0 still does not have fully
      compliant "shadow headers".
    
State of streams
      At least some older implementations don't have
      
std::ios_base, so you should use
      
std::ios::badbit, std::ios::failbit      and 
std::ios::eofbit and
      
std::ios::goodbit.
    
vector::at is missing (i.e. gcc 2.95.x)
      One solution is to add an autoconf-test for this:
      
	AC_MSG_CHECKING(for container::at)
	AC_TRY_COMPILE(
	[
	#include <vector>
	#include <deque>
	#include <string>
	
	using namespace std;
	],
	[
	deque<int> test_deque(3);
	test_deque.at(2);
	vector<int> test_vector(2);
	test_vector.at(1);
	string test_string("test_string");
	test_string.at(3);
	],
	[AC_MSG_RESULT(yes)
	AC_DEFINE(HAVE_CONTAINER_AT)],
	[AC_MSG_RESULT(no)])
      
      If you are using other (non-GNU) compilers it might be a good idea
      to check for 
string::at separately.
    
Using std::char_traits<char>::eof()
      
	#ifdef HAVE_CHAR_TRAITS
	#define CPP_EOF std::char_traits<char>::eof()
	#else
	#define CPP_EOF EOF
	#endif
      
    
Using string::clear()/string::erase()
      There are two functions for deleting the contents of a string:
      
clear and erase (the latter
      returns the string).
      
	void 
	clear() { _M_mutate(0, this->size(), 0); }
      
      
	basic_string& 
	erase(size_type __pos = 0, size_type __n = npos)
	{ 
	return this->replace(_M_check(__pos), _M_fold(__pos, __n),
	_M_data(), _M_data()); 
	}
      
      The implementation of 
erase seems to be more
      complicated (from libstdc++-v3), but 
clear is not
      implemented in gcc 2.95.x's libstdc++, so you should use
      
erase (which is probably faster than
      
operator=(charT*)).
    
GNU Extensions ostream::form and istream::scan
      These	are not supported any more - use
      
#sec-stringstream	stringstreams
 instead.	
    
Using stringstreams
      Libstdc++-v3 provides the new
      
i/ostringstream-classes, (<sstream>), but for compatibility
      with older implementations you still have to use
      
i/ostrstream (<strstream>):
      
	#ifdef HAVE_SSTREAM
	#include <sstream>
	#else
	#include <strstream>
	#endif
      
      
 strstream is considered to be
	    deprecated
	  
 strstream is limited to
	    
char	  
 with ostringstream you don't
	    have to take care of terminating the string or freeing its
	    memory
	  
 istringstream can be re-filled
	    (clear(); str(input);)
	  
    
      You can then use output-stringstreams like this:
      
	#ifdef HAVE_SSTREAM
	std::ostringstream oss;
	#else
	std::ostrstream oss;
	#endif
	oss << "Name=" << m_name << ", number=" << m_number << std::endl;
	...
	#ifndef HAVE_SSTREAM
	oss << std::ends; // terminate the char*-string
	#endif
	// str() returns char* for ostrstream and a string for ostringstream
	// this also causes ostrstream to think that the buffer's memory
	// is yours
	m_label.set_text(oss.str());
	#ifndef HAVE_SSTREAM
	// let the ostrstream take care of freeing the memory
	oss.freeze(false);
	#endif
      
    
      Input-stringstreams can be used similarly:
      
	std::string input;
	...
	#ifdef HAVE_SSTREAM
	std::istringstream iss(input);
	#else
	std::istrstream iss(input.c_str());
	#endif
	int i;
	iss >> i; 
      
      One (the only?) restriction is that an istrstream cannot be re-filled:
      
	std::istringstream iss(numerator);
	iss >> m_num;
	// this is not possible with istrstream
	iss.clear();
	iss.str(denominator);
	iss >> m_den;
      
      If you don't care about speed, you can put these conversions in
      a template-function:
      
	template <class X>
	void fromString(const string& input, X& any)
	{
	#ifdef HAVE_SSTREAM
	std::istringstream iss(input);
	#else
	std::istrstream iss(input.c_str());
	#endif
	X temp;
	iss >> temp;
	if (iss.fail())
	throw runtime_error(..)
	any = temp;
	}
      
      Another example of using stringstreams is in 
../21_strings/howto.htmlthis howto .
    
      I have read the Josuttis book on Standard C++, so some information
      comes from there. Additionally, there is information in
      "info iostream", which covers the old implementation that gcc 2.95.x
      uses.
    
About...
      Please send any experience, additions, corrections or questions to
      
mailto:fnatter@gmx.netfnatter@gmx.net  or for
      discussion to the libstdc++-v3-mailing-list.
    
