Keywords: ISO C++, backwards

Backwards Compatibility
Prev | Appendix B. Porting and Maintenance | Next

## Backwards Compatibility

### First

The first generation GNU C++ library was called libg++. It was a separate GNU project, although reliably paired with GCC. Rumors imply that it had a working relationship with at least two kinds of dinosaur.

Some background: libg++ was designed and created when there was no ISO standard to provide guidance. Classes like linked lists are now provided for by `std::list<T>` and do not need to be created by `genclass`. (For that matter, templates exist now and are well-supported, whereas genclass (mostly) predates them.)

There are other classes in libg++ that are not specified in the ISO Standard (e.g., statistical analysis). While there are a lot of really useful things that are used by a lot of people, the Standards Committee couldn't include everything, and so a lot of those “obvious” classes didn't get included.

That project is no longer maintained or supported, and the sources archived. For the desperate, the ftp.gnu.org server still has the libg++ source.

### Second

The second generation GNU C++ library was called libstdc++, or libstdc++-v2. It spans the time between libg++ and pre-ISO C++ standardization and is usually associated with the following GCC releases: egcs 1.x, gcc 2.95, and gcc 2.96.

The STL portions of that library are based on SGI/HP STL release 3.11.

That project is no longer maintained or supported, and the sources archived. The code was replaced and rewritten for libstdc++-v3.

### Third

The third generation GNU C++ library is called libstdc++, or libstdc++-v3.

The subset commonly known as the Standard Template Library (clauses 23 through 25 in C++98, mostly) is adapted from the final release of the SGI STL (version 3.3), with extensive changes.

A more formal description of the V3 goals can be found in the official design document.

Portability notes and known implementation limitations are as follows.

#### Pre-ISO headers removed

The pre-ISO C++ headers (`<iostream.h>`, `<defalloc.h>` etc.) are not supported.

For those of you new to ISO C++ (welcome, time travelers!), the ancient pre-ISO headers have new names. The C++ FAQ has a good explanation in What's the difference between <xxx> and <xxx.h> headers?.

Porting between pre-ISO headers and ISO headers is simple: headers like `<vector.h>` can be replaced with `<vector>` and a using directive `using namespace std;` can be put at the global scope. This should be enough to get this code compiling, assuming the other usage is correct.

#### Extension headers hash_map, hash_set moved to ext or backwards

At this time most of the features of the SGI STL extension have been replaced by standardized libraries. In particular, the `unordered_map` and `unordered_set` containers of TR1 and C++ 2011 are suitable replacements for the non-standard `hash_map` and `hash_set` containers in the SGI STL.

Header files `<hash_map>` and `<hash_set>` moved to `<ext/hash_map>` and `<ext/hash_set>`, respectively. At the same time, all types in these files are enclosed in `namespace __gnu_cxx`. Later versions deprecate these files, and suggest using TR1's `<unordered_map>` and `<unordered_set>` instead.

The extensions are no longer in the global or `std` namespaces, instead they are declared in the `__gnu_cxx` namespace. For maximum portability, consider defining a namespace alias to use to talk about extensions, e.g.:

          #ifdef __GNUC__
          #if __GNUC__ < 3
    	#include <hash_map.h>
    	namespace extension { using ::hash_map; }; // inherit globals
          #else
    	#include <backward/hash_map>
    	#if __GNUC__ == 3 && __GNUC_MINOR__ == 0
    	  namespace extension = std;               // GCC 3.0
    	#else
    	  namespace extension = ::__gnu_cxx;       // GCC 3.1 and later
    	#endif
          #endif
          #else      // ...  there are other compilers, right?
    	namespace extension = std;
          #endif

          extension::hash_map<int,int> my_map;

This is a bit cleaner than defining typedefs for all the instantiations you might need.

The following autoconf tests check for working HP/SGI hash containers.

    # AC_HEADER_EXT_HASH_MAP
    AC_DEFUN([AC_HEADER_EXT_HASH_MAP], [
      AC_CACHE_CHECK(for ext/hash_map,
      ac_cv_cxx_ext_hash_map,
      [AC_LANG_SAVE
      AC_LANG_CPLUSPLUS
      ac_save_CXXFLAGS="$CXXFLAGS"
      CXXFLAGS="$CXXFLAGS -Werror"
      AC_TRY_COMPILE([#include <ext/hash_map>], [using __gnu_cxx::hash_map;],
      ac_cv_cxx_ext_hash_map=yes, ac_cv_cxx_ext_hash_map=no)
      CXXFLAGS="$ac_save_CXXFLAGS"
      AC_LANG_RESTORE
      ])
      if test "$ac_cv_cxx_ext_hash_map" = yes; then
        AC_DEFINE(HAVE_EXT_HASH_MAP,,[Define if ext/hash_map is present. ])
      fi
    ])

    # AC_HEADER_EXT_HASH_SET
    AC_DEFUN([AC_HEADER_EXT_HASH_SET], [
      AC_CACHE_CHECK(for ext/hash_set,
      ac_cv_cxx_ext_hash_set,
      [AC_LANG_SAVE
      AC_LANG_CPLUSPLUS
      ac_save_CXXFLAGS="$CXXFLAGS"
      CXXFLAGS="$CXXFLAGS -Werror"
      AC_TRY_COMPILE([#include <ext/hash_set>], [using __gnu_cxx::hash_set;],
      ac_cv_cxx_ext_hash_set=yes, ac_cv_cxx_ext_hash_set=no)
      CXXFLAGS="$ac_save_CXXFLAGS"
      AC_LANG_RESTORE
      ])
      if test "$ac_cv_cxx_ext_hash_set" = yes; then
        AC_DEFINE(HAVE_EXT_HASH_SET,,[Define if ext/hash_set is present. ])
      fi
    ])

#### No `ios::nocreate/ios::noreplace`.

Historically these flags were used with iostreams to control whether new files are created or not when opening a file stream, similar to the `O_CREAT` and `O_EXCL` flags for the `open(2)` system call. Because iostream modes correspond to `fopen(3)` modes these flags are not supported. For input streams a new file will not be created anyway, so `ios::nocreate` is not needed. For output streams, a new file will be created if it does not exist, which is consistent with the behaviour of `fopen`.

When one of these flags is needed a possible alternative is to attempt to open the file using std::ifstream first to determine whether the file already exists or not. This may not be reliable however, because whether the file exists or not could change between opening the std::istream and re-opening with an output stream. If you need to check for existence and open a file as a single operation then you will need to use OS-specific facilities outside the C++ standard library, such as `open(2)`.

#### No `stream::attach(int fd)`

Phil Edwards writes: It was considered and rejected for the ISO standard. Not all environments use file descriptors. Of those that do, not all of them use integers to represent them.

For a portable solution (among systems which use file descriptors), 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.

An extension is available that implements this. `<ext/stdio_filebuf.h>` contains a derived class called `__gnu_cxx::stdio_filebuf`. This class can be constructed from a C `FILE*` or a file descriptor, and provides the `fd()` function.

For another example of this, refer to fdstream example by Nicolai Josuttis.

#### Support for C++98 dialect.

Check for complete library coverage of the C++1998/2003 standard.

    # AC_HEADER_STDCXX_98
    AC_DEFUN([AC_HEADER_STDCXX_98], [
      AC_CACHE_CHECK(for ISO C++ 98 include files,
      ac_cv_cxx_stdcxx_98,
      [AC_LANG_SAVE
      AC_LANG_CPLUSPLUS
      AC_TRY_COMPILE([
        #include <cassert>
        #include <cctype>
        #include <cerrno>
        #include <cfloat>
        #include <ciso646>
        #include <climits>
        #include <clocale>
        #include <cmath>
        #include <csetjmp>
        #include <csignal>
        #include <cstdarg>
        #include <cstddef>
        #include <cstdio>
        #include <cstdlib>
        #include <cstring>
        #include <ctime>

        #include <algorithm>
        #include <bitset>
        #include <complex>
        #include <deque>
        #include <exception>
        #include <fstream>
        #include <functional>
        #include <iomanip>
        #include <ios>
        #include <iosfwd>
        #include <iostream>
        #include <istream>
        #include <iterator>
        #include <limits>
        #include <list>
        #include <locale>
        #include <map>
        #include <memory>
        #include <new>
        #include <numeric>
        #include <ostream>
        #include <queue>
        #include <set>
        #include <sstream>
        #include <stack>
        #include <stdexcept>
        #include <streambuf>
        #include <string>
        #include <typeinfo>
        #include <utility>
        #include <valarray>
        #include <vector>
      ],,
      ac_cv_cxx_stdcxx_98=yes, ac_cv_cxx_stdcxx_98=no)
      AC_LANG_RESTORE
      ])
      if test "$ac_cv_cxx_stdcxx_98" = yes; then
        AC_DEFINE(STDCXX_98_HEADERS,,[Define if ISO C++ 1998 header files are present. ])
      fi
    ])

#### Support for C++TR1 dialect.

Check for library coverage of the TR1 standard.

    # AC_HEADER_STDCXX_TR1
    AC_DEFUN([AC_HEADER_STDCXX_TR1], [
      AC_CACHE_CHECK(for ISO C++ TR1 include files,
      ac_cv_cxx_stdcxx_tr1,
      [AC_LANG_SAVE
      AC_LANG_CPLUSPLUS
      AC_TRY_COMPILE([
      #include <tr1/array>
      #include <tr1/ccomplex>
      #include <tr1/cctype>
      #include <tr1/cfenv>
      #include <tr1/cfloat>
      #include <tr1/cinttypes>
      #include <tr1/climits>
      #include <tr1/cmath>
      #include <tr1/complex>
      #include <tr1/cstdarg>
      #include <tr1/cstdbool>
      #include <tr1/cstdint>
      #include <tr1/cstdio>
      #include <tr1/cstdlib>
      #include <tr1/ctgmath>
      #include <tr1/ctime>
      #include <tr1/cwchar>
      #include <tr1/cwctype>
      #include <tr1/functional>
      #include <tr1/memory>
      #include <tr1/random>
      #include <tr1/regex>
      #include <tr1/tuple>
      #include <tr1/type_traits>
      #include <tr1/unordered_set>
      #include <tr1/unordered_map>
      #include <tr1/utility>
      ],,
      ac_cv_cxx_stdcxx_tr1=yes, ac_cv_cxx_stdcxx_tr1=no)
      AC_LANG_RESTORE
      ])
      if test "$ac_cv_cxx_stdcxx_tr1" = yes; then
        AC_DEFINE(STDCXX_TR1_HEADERS,,[Define if ISO C++ TR1 header files are present. ])
      fi
    ])

An alternative is to check just for specific TR1 includes, such as <unordered_map> and <unordered_set>.

    # AC_HEADER_TR1_UNORDERED_MAP
    AC_DEFUN([AC_HEADER_TR1_UNORDERED_MAP], [
      AC_CACHE_CHECK(for tr1/unordered_map,
      ac_cv_cxx_tr1_unordered_map,
      [AC_LANG_SAVE
      AC_LANG_CPLUSPLUS
      AC_TRY_COMPILE([#include <tr1/unordered_map>], [using std::tr1::unordered_map;],
      ac_cv_cxx_tr1_unordered_map=yes, ac_cv_cxx_tr1_unordered_map=no)
      AC_LANG_RESTORE
      ])
      if test "$ac_cv_cxx_tr1_unordered_map" = yes; then
        AC_DEFINE(HAVE_TR1_UNORDERED_MAP,,[Define if tr1/unordered_map is present. ])
      fi
    ])

    # AC_HEADER_TR1_UNORDERED_SET
    AC_DEFUN([AC_HEADER_TR1_UNORDERED_SET], [
      AC_CACHE_CHECK(for tr1/unordered_set,
      ac_cv_cxx_tr1_unordered_set,
      [AC_LANG_SAVE
      AC_LANG_CPLUSPLUS
      AC_TRY_COMPILE([#include <tr1/unordered_set>], [using std::tr1::unordered_set;],
      ac_cv_cxx_tr1_unordered_set=yes, ac_cv_cxx_tr1_unordered_set=no)
      AC_LANG_RESTORE
      ])
      if test "$ac_cv_cxx_tr1_unordered_set" = yes; then
        AC_DEFINE(HAVE_TR1_UNORDERED_SET,,[Define if tr1/unordered_set is present. ])
      fi
    ])

#### Support for C++11 dialect.

Check for baseline language coverage in the compiler for the C++11 standard.

    # AC_COMPILE_STDCXX_11
    AC_DEFUN([AC_COMPILE_STDCXX_11], [
      AC_CACHE_CHECK(if g++ supports C++11 features without additional flags,
      ac_cv_cxx_compile_cxx11_native,
      [AC_LANG_SAVE
      AC_LANG_CPLUSPLUS
      AC_TRY_COMPILE([
      template <typename T>
        struct check final
        {
          static constexpr T value{ __cplusplus };
        };

        typedef check<check<bool>> right_angle_brackets;

        int a;
        decltype(a) b;

        typedef check<int> check_type;
        check_type c{};
        check_type&& cr = static_cast<check_type&&>(c);

        static_assert(check_type::value == 201103L, "C++11 compiler");],,
      ac_cv_cxx_compile_cxx11_native=yes, ac_cv_cxx_compile_cxx11_native=no)
      AC_LANG_RESTORE
      ])

      AC_CACHE_CHECK(if g++ supports C++11 features with -std=c++11,
      ac_cv_cxx_compile_cxx11_cxx,
      [AC_LANG_SAVE
      AC_LANG_CPLUSPLUS
      ac_save_CXXFLAGS="$CXXFLAGS"
      CXXFLAGS="$CXXFLAGS -std=c++11"
      AC_TRY_COMPILE([
      template <typename T>
        struct check final
        {
          static constexpr T value{ __cplusplus };
        };

        typedef check<check<bool>> right_angle_brackets;

        int a;
        decltype(a) b;

        typedef check<int> check_type;
        check_type c{};
        check_type&& cr = static_cast<check_type&&>(c);

        static_assert(check_type::value == 201103L, "C++11 compiler");],,
      ac_cv_cxx_compile_cxx11_cxx=yes, ac_cv_cxx_compile_cxx11_cxx=no)
      CXXFLAGS="$ac_save_CXXFLAGS"
      AC_LANG_RESTORE
      ])

      AC_CACHE_CHECK(if g++ supports C++11 features with -std=gnu++11,
      ac_cv_cxx_compile_cxx11_gxx,
      [AC_LANG_SAVE
      AC_LANG_CPLUSPLUS
      ac_save_CXXFLAGS="$CXXFLAGS"
      CXXFLAGS="$CXXFLAGS -std=gnu++11"
      AC_TRY_COMPILE([
      template <typename T>
        struct check final
        {
          static constexpr T value{ __cplusplus };
        };

        typedef check<check<bool>> right_angle_brackets;

        int a;
        decltype(a) b;

        typedef check<int> check_type;
        check_type c{};
        check_type&& cr = static_cast<check_type&&>(c);

        static_assert(check_type::value == 201103L, "C++11 compiler");],,
      ac_cv_cxx_compile_cxx11_gxx=yes, ac_cv_cxx_compile_cxx11_gxx=no)
      CXXFLAGS="$ac_save_CXXFLAGS"
      AC_LANG_RESTORE
      ])

      if test "$ac_cv_cxx_compile_cxx11_native" = yes ||
         test "$ac_cv_cxx_compile_cxx11_cxx" = yes ||
         test "$ac_cv_cxx_compile_cxx11_gxx" = yes; then
        AC_DEFINE(HAVE_STDCXX_11,,[Define if g++ supports C++11 features. ])
      fi
    ])

Check for library coverage of the C++2011 standard. (Some library headers are commented out in this check, they are not currently provided by libstdc++).

    # AC_HEADER_STDCXX_11
    AC_DEFUN([AC_HEADER_STDCXX_11], [
      AC_CACHE_CHECK(for ISO C++11 include files,
      ac_cv_cxx_stdcxx_11,
      [AC_REQUIRE([AC_COMPILE_STDCXX_11])
      AC_LANG_SAVE
      AC_LANG_CPLUSPLUS
      ac_save_CXXFLAGS="$CXXFLAGS"
      CXXFLAGS="$CXXFLAGS -std=gnu++11"

      AC_TRY_COMPILE([
        #include <cassert>
        #include <ccomplex>
        #include <cctype>
        #include <cerrno>
        #include <cfenv>
        #include <cfloat>
        #include <cinttypes>
        #include <ciso646>
        #include <climits>
        #include <clocale>
        #include <cmath>
        #include <csetjmp>
        #include <csignal>
        #include <cstdalign>
        #include <cstdarg>
        #include <cstdbool>
        #include <cstddef>
        #include <cstdint>
        #include <cstdio>
        #include <cstdlib>
        #include <cstring>
        #include <ctgmath>
        #include <ctime>
        // #include <cuchar>
        #include <cwchar>
        #include <cwctype>

        #include <algorithm>
        #include <array>
        #include <atomic>
        #include <bitset>
        #include <chrono>
        // #include <codecvt>
        #include <complex>
        #include <condition_variable>
        #include <deque>
        #include <exception>
        #include <forward_list>
        #include <fstream>
        #include <functional>
        #include <future>
        #include <initializer_list>
        #include <iomanip>
        #include <ios>
        #include <iosfwd>
        #include <iostream>
        #include <istream>
        #include <iterator>
        #include <limits>
        #include <list>
        #include <locale>
        #include <map>
        #include <memory>
        #include <mutex>
        #include <new>
        #include <numeric>
        #include <ostream>
        #include <queue>
        #include <random>
        #include <ratio>
        #include <regex>
        #include <scoped_allocator>
        #include <set>
        #include <sstream>
        #include <stack>
        #include <stdexcept>
        #include <streambuf>
        #include <string>
        #include <system_error>
        #include <thread>
        #include <tuple>
        #include <typeindex>
        #include <typeinfo>
        #include <type_traits>
        #include <unordered_map>
        #include <unordered_set>
        #include <utility>
        #include <valarray>
        #include <vector>
      ],,
      ac_cv_cxx_stdcxx_11=yes, ac_cv_cxx_stdcxx_11=no)
      AC_LANG_RESTORE
      CXXFLAGS="$ac_save_CXXFLAGS"
      ])
      if test "$ac_cv_cxx_stdcxx_11" = yes; then
        AC_DEFINE(STDCXX_11_HEADERS,,[Define if ISO C++11 header files are present. ])
      fi
    ])

As is the case for TR1 support, these autoconf macros can be made for a finer-grained, per-header-file check. For `<unordered_map>`

    # AC_HEADER_UNORDERED_MAP
    AC_DEFUN([AC_HEADER_UNORDERED_MAP], [
      AC_CACHE_CHECK(for unordered_map,
      ac_cv_cxx_unordered_map,
      [AC_REQUIRE([AC_COMPILE_STDCXX_11])
      AC_LANG_SAVE
      AC_LANG_CPLUSPLUS
      ac_save_CXXFLAGS="$CXXFLAGS"
      CXXFLAGS="$CXXFLAGS -std=gnu++11"
      AC_TRY_COMPILE([#include <unordered_map>], [using std::unordered_map;],
      ac_cv_cxx_unordered_map=yes, ac_cv_cxx_unordered_map=no)
      CXXFLAGS="$ac_save_CXXFLAGS"
      AC_LANG_RESTORE
      ])
      if test "$ac_cv_cxx_unordered_map" = yes; then
        AC_DEFINE(HAVE_UNORDERED_MAP,,[Define if unordered_map is present. ])
      fi
    ])

    # AC_HEADER_UNORDERED_SET
    AC_DEFUN([AC_HEADER_UNORDERED_SET], [
      AC_CACHE_CHECK(for unordered_set,
      ac_cv_cxx_unordered_set,
      [AC_REQUIRE([AC_COMPILE_STDCXX_11])
      AC_LANG_SAVE
      AC_LANG_CPLUSPLUS
      ac_save_CXXFLAGS="$CXXFLAGS"
      CXXFLAGS="$CXXFLAGS -std=gnu++11"
      AC_TRY_COMPILE([#include <unordered_set>], [using std::unordered_set;],
      ac_cv_cxx_unordered_set=yes, ac_cv_cxx_unordered_set=no)
      CXXFLAGS="$ac_save_CXXFLAGS"
      AC_LANG_RESTORE
      ])
      if test "$ac_cv_cxx_unordered_set" = yes; then
        AC_DEFINE(HAVE_UNORDERED_SET,,[Define if unordered_set is present. ])
      fi
    ])

Some C++11 features first appeared in GCC 4.3 and could be enabled by `-std=c++0x` and `-std=gnu++0x` for GCC releases which pre-date the 2011 standard. Those C++11 features and GCC's support for them were still changing until the 2011 standard was finished, but the autoconf checks above could be extended to test for incomplete C++11 support with `-std=c++0x` and `-std=gnu++0x`.

#### `Container::iterator_type` is not necessarily `Container::value_type*`

This is a change in behavior from older versions. Now, most iterator_type typedefs in container classes are POD objects, not value_type pointers.

Prev | Up | Next
API Evolution and Deprecation History | Home | Appendix C. Free Software Needs Free Documentation