DIGITAL logo   C++ Graphic
    Updated: 02 September 1998
  DIGITAL C++

DIGITAL C++
Using DIGITAL C++ for Compaq's DIGITAL UNIX


Previous Contents Index


Chapter 7
The C++ Standard Library

The C++ Standard Library provided with this release defines a complete specification of the Final Draft International ANSI C++ Standard (FDIS), with some differences, as described in the DIGITAL C++ Version 6.1 Release Notes for Compaq's DIGITAL UNIX.

The Standard Library in this release includes the ANSI locale and iostream libraries.

Portions of the ANSI C++ Standard Library have been implemented in DIGITAL C++ using source licensed from and copyrighted by Rogue Wave Software, Inc. Information pertaining to the C++ Standard Library has been edited and incorporated into DIGITAL C++ documentation with permission of Rogue Wave Software, Inc. All rights reserved.

Some of the components in the C++ Standard Library are designed to replace nonstandard components that are currently distributed in the DIGITAL C++ Class Library. DIGITAL will continue to provide the DIGITAL C++ Class Library in its nonstandard form. However, you now have the option of using new standard components.

The following sections provide more information on the DIGITAL C++ implementation of the Standard Library, including upward compatibility, compiling, linking, and thread safety.

7.1 Important Compatibility Information

Because the standardization process for the C++ Standard Library is not yet completed, DIGITAL cannot guarantee that this version of the library is compatible with any past or future releases. We ship the run-time portion of the library in object form, not in shareable form, to emphasize this situation.

The following sections describe specific compatibility issues.

7.1.1 -[no]using_std Compiler Compatibility Switch

All standard library names in DIGITAL C++ are inside the namespace std. Typically you would qualify each standard library name with std:: or put using namespace std; at the top of your source file.

To make things easier for existing users, using namespace std; is included in a file provided with every standard library header when you are in arm, cfront, ms, or ansi compiler modes. This is not the default in strict_ansi or strict_ansi_errors mode.

The compiler supplied switches -nousing_std and -using_std can be used to override the default. -nousing_std turns the implicit using namespace std off; -using_std turns it on.

7.1.2 Pre-ANSI/ANSI IOStreams Compatibility

The C++ Standard Library offers support for the standard IOStreams library based on the Final Draft International ANSI C++ Standard (FDIS). These standard iostream classes are in the new header files <iostream>, <ostream>, <istream>, and so on (no .h or .hxx extension).

For backward compatibility, the pre-ANSI IOStream library is still provided in the old header files iostream.hxx, istream.hxx, and so on. The two libraries exhibit subtle differences and incompatibilities.

Users can choose which version (ANSI or pre-ANSI) of iostreams they want to use; either version of iostreams can be integrated seamlessly with the new Standard Library and string functionality.

To accomplish this goal, macros called __USE_STD_IOSTREAM and
__NO_USE_STD_IOSTREAM are provided. If you do not set these macros explicitly, the default in arm, cfront, ms, and ansi modes is to use the pre-ANSI IOStream library. In strict_ansi and strict_ansi_errors mode, the default is to use the ANSI IOStream library.

You override the default by defining __USE_STD_IOSTREAM or
__NO_USE_STD_IOSTREAM on either the command line or in your source code.

In arm, cfront, ms, and ansi modes, specify use of the ANSI iostreams in one of the following ways:

  • Enter -D__USE_STD_IOSTREAM on the command line.
  • Put #define __USE_STD_IOSTREAM in your source file before any include files.

In strict_ansi and strict_ansi_errors modes specify use of the pre-ANSI iostreams in one of the following ways:

  • Enter -D__NO_USE_STD_IOSTREAM on the command line.
  • Put #define __NO_USE_STD_IOSTREAM in your source file before any include files.

A #error warning appears:

  1. If you have explicitly included the wrong header for the current mode. For example, if you say #include <iostream> (an ANSI header) and you are in -std ansi, -std cfront, -std ms or -std arm mode, and if you have not entered -D__USE_STD_IOSTREAM on the command line, an error message appears.
  2. If you are in -std strict_ansi or -std strict_ansi_errors, and you enter #include <iostream.h>, an error message appears unless you also enter -D__NO_USE_STD_IOSTREAM.

Many of the other headers, <string> for example, make use of the iostream classes. The default version of iostreams that is automatically included when you include one of these headers depends on the mode you compile in and the setting of the macros __USE_STD_IOSTREAM and __NO_USE_STD_IOSTREAM as described earlier.

Because the standard locale class and the standard iostream class are so closely tied, you cannot use the standard locale class with the pre-standard iostream classes. If you want to use locale, you must use the standard iostream classes.

It is possible to use the pre-ANSI and the ANSI IOStream library in the same source file, because all the standard iostream names (that is, cout, cin, and so on) are in namespace std, and all the pre-ANSI names are in the global namespace. This is not recommended, though, because there is no guarantee of stream objects being the same size or, for example, of ::cout being in sync with std::cout.

To do this in all modes, include a pre-ANSI iostreams header before an ANSI iostreams header as follows:


 
  #undef __USE_STD_IOSTREAM 
  #include <iostream.h> 
  #define __USE_STD_IOSTREAM 
  #include <iostream> 
 
  int main() 
  { 
    std::string s("abc"); 
    ::cout << "abc" << endl;         // pre-standard iostreams 
    std::cout << "abc" << std::endl; // standard iostreams 
    return 0; 
  } 
 

To do this in all modes, if you include an ANSI iostreams header before a pre-ANSI iostreams header, follow these steps:

  1. Compile your source using -nousing_std.
  2. Use the __USE_STD_IOSTREAM macro as shown in the following example. You must define __USE_STD_IOSTREAM at the end of your include file list so that the template definition files (the .cc files) are included in the correct mode.


     
      // Compile this with -nousing_std 
      #define __USE_STD_IOSTREAM 
      #include <iostream> 
      #undef __USE_STD_IOSTREAM 
      #include <iostream.h> 
      #define __USE_STD_IOSTREAM // so the template definition files are ok 
     
      int main() 
      { 
        std::string s("abc"); 
        ::cout << "abc" << endl; // pre-standard iostreams 
        std::cout << "abc" << std::endl; // standard iostreams 
        return 0; 
      } 
     
    

7.1.3 Support for pre-ANSI and ANSI operator new()

The Standard C++ Library supports the ANSI implementation of the operator new() as well as the pre-ANSI implementation of operator new(). The ANSI implementation throws std::bad_alloc on memory allocation failures.

The pre-ANSI implementation of the operator new() returns 0 on memory allocation failures. Because the ANSI behavior is incompatible with pre-ANSI applications, a compile time switch has been added (-[no]stdnew) to control whether calls to ANSI new() or pre-ANSI new are generated.

The following examples show how ANSI versus pre-ANSI new() check for memory allocation. First, here is an ANSI new() check for memory allocation failure:


 
            try { 
                myobjptr = new (myobjptr); 
            } 
            catch (std::bad_alloc e) { 
                cout << e.what() << endl; 
            }; 
 

The following example shows a pre-ANSI new() check for memory allocation failure:


            if ((myobjptr = new (myobjptr)) == 0) 
                call_failure_routine(); 

When upgrading pre-ANSI new() code to work with the C++ Standard Library you also can use the nothrow version of ANSI new(). To do so in the pre-ANSI example, you could recode it as follows:


            if ((myobjptr = new (myobjptr, nothrow)) == 0) 
                 call_failure_routine(); 

Two command line switches are available in the compiler to control whether calls are generated to the ANSI or pre-ANSI implementation of operator new(). Use the -stdnew switch to generate calls to the ANSI new() implementation. Use the -nostdnew switch to generate calls to the pre-ANSI new() implementation.

You can override global new() by declaring your own functions.

When compiling with -std ansi, -std strict_ansi, and -std strict_ansi_errors, -stdnew is the default. When compiling with -std arm, -std cfront, and -std ms, -nostdnew is the default. The compiler defines the macro __STDNEW when the -stdnew option is specified.

7.1.4 Support for Global array new and delete Operators

DIGITAL C++ Version 6.0 fully supports the array new and delete operators as described in the ANSI standard. Previous versions did not.

You might therefore encounter a compatibility problem if you have overridden the run-time library's operator new() with your own version.

For example:


 
#include <iostream.h> 
 
inline void* operator new(size_t s) { 
 cout << "called my operator new" << endl; 
 return 0; 
} 
 
void main() { 
 new int;    // ok, this still calls your own 
 new int[4]; // In V6.0 calls the C++ library's operator new[] 
} 
 

In older versions, both new int and new int[4] would generate a call to operator new() (they would just be asking for different sizes). With the current compiler, new int still generates a call to operator new(). However, new int[4] generates a call to operator new()[]. This means that if you still want to override the library's operator new you must do one of the following:

  1. Provide your own definition of operator new()[].
  2. Use the -noglobal_array_new switch.

The -noglobal_array_new switch converts all expressions such as new int[4] to calls to the global operator new(), thus preserving compatibility with older compiler versions.

This switch has no effect on class-specific array operator new and delete; it affects only the global operators.

When compiling with -std ansi, -std strict_ansi, -std strict_ansi_errors, and -std ms modes, -global_array_new is the default. When compiling with -std arm or -std cfront modes, -noglobal_array_new is the default. A macro __GLOBAL_ARRAY_NEW is predefined by the compiler when -global_array_new is used.

7.2 How to Build Programs Using the C++ Standard Library

When you use the cxx command to compile and link programs that use the C++ Standard Library, no special switches are required. The DIGITAL C++ driver automatically includes the Standard Library run-time support (-lcxxstd) on the link command, and automatic template instantiation (-pt) is the default mode.

For example, to build a program called prog.cxx that uses the Standard Library, you can simply use the following command:


cxx prog.cxx 

Thread Safety

The Standard Library provided with this release is thread safe but not thread reentrant. Thread safe means that all library internal and global data is protected from simultaneous access by multiple threads. In this way, internal buffers as well as global data like cin and cout are protected during each individual library operation. Users, however, are responsible for protecting their own objects.

According to the C++ standard, results of recursive initialization are undefined. To guarantee thread safety, the compiler inserts code to implement a spinlock if another thread is initializing local static data. If recursive initialization occurs, the code deadlocks even if threads are not used.

7.3 Optional Switch to Control Buffering

The inplace_merge, stable_sort, and stable_partition algorithms require the use of a temporary buffer. Two methods are available for allocating this buffer:

  • Preallocate 16K bytes of space on the stack.
  • Allocate the required amount of storage dynamically.

By default, the current DIGITAL C++ library makes use of the preallocated buffer, which avoids the overhead of run-time allocation. If your application requires a buffer that exceeds 16K, it can not take advantage of this default.

If you are concerned with minimizing the use of stack space in your program, or if your application requires a buffer that exceeds 16K, define the __DEC_DYN_ALLOC macro to enable dynamic buffering. Do this by adding the following to your compile command line:


-D__DEC_DYN_ALLOC 

7.4 Enhanced Compile-time Performance of ANSI IOStreams

To speed up the compile-time performance of programs that use the standard iostream and locale components, many common template instantiations of these components have been included in the Standard Library.

To force programs to create instantiations at compile-time (for example, if you want to debug them and thus need them to be compiled with the -gall option), define the macro __FORCE_INSTANTIATIONS on the command line. This definition suppresses the #pragma do_not_instantiate directives in the headers so that the compiler creates the instantiations in your repository directory.

You must then specify the -ptr option to force the compiler to link your instantiations instead of those in the Standard Library.

7.5 Upgrading from the DIGITAL C++ Class Library to the Standard Library Provided with Version 6.n

The following discussion guides you through upgrading the DIGITAL C++ Class Library code to use the Standard Library, specifically replacing the vector and stack classes in the vector.hxx header file to the Standard Library vector and stack classes.

7.5.1 Upgrading from the DIGITAL C++ Class Library Vector to the Standard Library Vector

To change your code from using the DIGITAL C++ Class Library vector to the Standard Library vector, consider the following actions:

  • Change the name of your #include statement from <vector.h> or <vector.hxx> to <vector>.
  • Remove the vectordeclare and vectorimplement declarations from your code.
  • Change all vector(type) declarations to vector<type>. For example, vector(int) vi should become vector<int> vi.
  • Note that the following member functions are replaced in the Standard Library:
    Nonstandard Vector Function Standard Library Vector Function
    elem(int index) operator[](size_t index)
    (no bounds checking)
    operator[](int index) at(size_t index)
    (bounds checking)
    setsize(int newsize) resize(size_t newsize)
  • When copying vectors of unequal lengths, note that the Standard Library vector has a different behavior as follows:
    When using the Standard Library vector, if the target vector is smaller than the source vector, the target vector automatically increases to accommodate the additional elements.
    The DIGITAL C++ Class Library vector displays an error and aborts when this situation occurs.
  • Another difference in behavior occurs when you specify a negative index for a vector.
    The DIGITAL C++ Class Library vector class detects the negative specification and issues an error message. However, the Standard Library vector silently converts the negative value to a large positive value, because indices are represented as type size_t (unsigned long) rather than int.
  • When an out-of-bounds error occurs, the existing vector prints an error message and aborts, whereas the Standard Library vector throws an out-of-range object.

7.5.2 Upgrading from the DIGITAL C++ Class Library Stack to the Standard Library Stack

To change your code from using the existing stack to the Standard Library stack, consider the following actions:

  • Change the name of your #include statement from <vector.h> or <vector.hxx> to <stack>.
  • Remove the stackdeclare and stackimplement declarations from your code.
  • Change all stack(type) declarations to stack<type, deque<type> >. For example, stack(int) si should become stack<int, deque<int> > si.
  • Do not specify an initial size for a Standard Library stack. The stack must start out empty and grow dynamically (as you push and pop).
  • The following member functions are not supported or have different semantics:
    Class Library Stack Standard Library Stack
    size_used() Does not exist because the size() function always is equal to the size_used() function.
    full() Does not exist because the stack always is full.
    pop() Does not return the popped element. To simulate DIGITAL C++ Class Library behavior, first obtain the element as the return type from the top() function and then call the pop() function. For example, change int i=s.pop(); to the following:
    int i=s.top();
    
    s.pop();
  • The Standard Library stack differs from the DIGITAL C++ Class Library stack in the way errors are detected. Unlike the nonstandard stack, you cannot overflow a Standard Library stack because space is allocated dynamically as you push elements onto the stack.

7.5.3 Upgrading from the DIGITAL C++ String Package Code

The Standard basic_string library can replace the DIGITAL C++ Class Library String Package.

The following list guides you through upgrading nonstandard code to use the Standard Library basic_string:

  • Change #include <string.h> or #include <string.hxx> to #include <string>.
  • Change all declarations of String to string (uppercase S to lowercase s).
  • The String Package allowed assignment of a string directly to a char *; however, the basic_string library does not allow this. You can assign the string's const char* representation using the c_str() or data() basic_string member functions. For example:


    string s("abc"); 
    char* cp = s; // not allowed 
    const char* cp = s.data(); // ok 
    

    The state of the string is undefined if the result of data() is cast to a non-const char* and then the value of that char* is changed.

  • The String Package member functions upper() and lower() are not in the basic_string library. You can write these functions as nonmember functions, as follows:


    template <class charT, class traits, class Allocator> 
    inline 
    basic_string<charT, traits, Allocator> 
    upper(const basic_string<charT,traits, Allocator>& str) { 
            basic_string<charT, traits, Allocator> newstr(str); 
            for (size_t index = 0; index < str.length(); index++) 
                    if (islower(str[index])) 
                            newstr[index] = toupper(str[index]);  
            return newstr; 
    } 
     
    template <class charT, class traits, class Allocator> 
    inline 
    basic_string<charT, traits, Allocator> 
    lower(const basic_string<charT,traits, Allocator>& str) { 
            basic_string<charT, traits, Allocator> newstr(str); 
            for (size_t index = 0; index < str.length(); index++) 
                    if (isupper(str[index])) 
                            newstr[index] = tolower(str[index]);  
            return newstr; 
    } 
    

    Then instead of calling upper() and lower() as member functions of the basic_string, pass the string as an argument. For example:


    s2 = s1.upper(); // does not compile 
    s2 = upper(s1); // ok 
    

  • The String Package match() member function does not exist. Equivalent functionality exists in the Standard Library algorithm mismatch(), although using it is more complicated. For example:


     
    string s1("abcdef"); 
    string s2("abcdgf"); 
    assert(s1.match(s2)==4); // does not compile 
    pair<string::iterator,string::iterator> p(0,0); // ok 
    p=mismatch(s1.begin(),s1.end(),s2.begin()); 
    assert(p.first-s1.begin()==4); 
    string s3 = s1; 
    p=mismatch(s1.begin(),s1.end(),s3.begin()); 
    assert(p.first == s1.end()); // everything matched 
     
    

  • The String Package index() member function does not exist. The basic_string library equivalent is find().
  • The String Package constructor that takes two positional parameters (a start and end position) and constructs a new string does not exist. It is replaced in the basic_string library with the member function substr(). For example:


    string s("abcde"); 
    string s2 = s1(1,3); // does not compile 
    string s2 = s1.substr(1,3); // ok 
    

  • Many previously undetected run-time errors now throw standard exceptions in the String library.

7.5.4 Upgrading from the DIGITAL C++ Class Library Complex to the ANSI Complex Class

This section explains how to upgrade from the pre-ANSI DIGITAL C++ complex library to the current DIGITAL C++ standard complex library.

In the ANSI library, complex objects are templatized on the type of the real and imaginary parts, the pre-ANSI DIGITAL C++ library, complex objects are not templatized. The pre-ANSI library assumes the type is double, whereas the new library provides specializations for float, double, and long double as well as allowing users to specialize on their own floating point types.

Mathematical error checking is not supported in the ANSI library. Users who rely on detection of underflow, overflow, and divide by zero should continue using the pre-ANSI DIGITAL C++ complex library.

The following is a detailed list of important changes:

  • Change #include <complex.h> or #include <complex.hxx> to #include <complex>.
  • Change all declarations of complex to complex<double>, for example:


    complex c; 
    

    Change to:


    complex<double> c;  
    

  • The polar() function no longer supplies a default value of 0 for the second argument. Users will have to explicitly add it to any calls that have only one argument, for example:


    complex c; 
    c = polar(c); // get polar 
    

    Change to:


    complex<double> c; 
    c = polar(c,0.0); 
    

  • If you are calling a mathematical function or mathematical operator that takes scalars as arguments (polar() for example), then you must adjust the arguments you pass in to be the same type as the complex template parameter type. For example, you would have to change:


    complex c = polar(0,0); 
    complex c2 = c+1; 
    

    Change to:


     
    complex<double> c = polar(0.0,0.0); // 0.0 is double 
    complex<double> c2= c + 1.0; // 1.0 is double 
     
    

  • The complex_zero variable is not declared in the complex header file. If you want to use it, you will have to declare it yourself. For example, add the following to the top of your source file:


    static const complex<double> complex_zero(0.0,0.0); 
    

  • The sqr() and arg1() functions are gone. If you want to continue to use them, you should define them in one of your own headers, using the following definitions:


     
    template <class T> 
    inline complex<T> sqr(const complex<T>& a) 
    { 
       return complex<T>(real(a) * real(a) - imag(a) * imag(a), 
            2 * real(a) * imag(a)); 
    } 
     
    template <class T> 
    inline T arg1(const complex<T>& a) 
     
    { 
        double val = arg(a); 
     
        if(val > -M_PI && val <= M_PI) 
            return val; 
     
        if(val > M_PI) 
            return val - (2*M_PI); 
     
        // val <= -PI 
        return val + (2*M_PI); 
    } 
    

  • The pow(complex, int) function is no longer provided. You must use pow(complex<double>, double). This means changing calls such as:


    pow(c,1); 
    

    to:


    pow(c,1.0); 
    

    This might yield different results. If the function previously was underflowing or overflowing, it might not continue to happen.

  • The complex output operator (<<) does not insert a space between the comma and the imaginary part. If you want the space, you would need to print the real and imaginary parts separately, adding your own comma and space; that is:


    complex<double> c; 
    cout << "(" << c.real() << ", " << c.imag() << ")"; // add extra space 
    

  • The complex input operator (>>) does not raise an Objection if bad input is detected; it instead sets input stream's state to ios::failbit.
  • Floating point overflow, underflow, and divide by zero do not set errno and will cause undefined behavior. DIGITAL plans to do complex error checking and error notification in a subsequent release.
  • You should no longer need to explicitly link your program with the complex library. It is automatically linked in as part of the Standard Library. However, you must still explicitly link in the C math library, as shown in the following example:


    #include <complex> 
     
    int main() { 
            complex<double> c1(1,1), c2(3.14,3.14); 
            cout << "c2/c1: " << c2/c1 << endl; 
    } 
    

7.5.5 Upgrading from the DIGITAL C++ IOStreams library to the DIGITAL C++ Standard Library

This section explains how to upgrade from the pre-ANSI DIGITAL C++ IOStreams library to the ANSI DIGITAL C++ IOStreams library. In this section, pre-ANSI IOStreams refers to versions of the IOStreams library found in the DIGITAL C++ Class Library; ANSI IOStreams refers to versions found in the DIGITAL C++ Standard Library.

There are a number of differences between the pre-ANSI and ANSI IOstream library. One major difference between the pre-ANSI and ANSI IOstream library is that the ANSI library is templatized on the object input/output on which operations are being performed. In the pre-ANSI library, IOStreams has no templates. The ANSI library also provides specializations for char and wchar_t.

Important differences are as follows:

  • With the current compiler, you access the pre-ANSI IOstream library by default in non strict_ansi compiler modes. You can control the version of IOStreams you use with the __USE_STD_IOSTREAM and __NO_USE_STD_IOSTREAM macros. If you want to use the ANSI IOstream library, do either of the following:
    • -D__USE_STD_IOSTREAM on the command line.
    • #define __USE_STD_IOSTREAM in your source file before any include files.
  • Header names are different in the ANSI library, so to use ANSI IOStreams, change the IOStreams headers you include as follows:
    From To
    #include <iostream.h>
    #include <iostream.hxx>
    #include <iostream>
    #include <fstream.h>
    #include <fstream.hxx>
    #include <fstream>
    #include <strstream.h>
    #include <strstream.hxx>
    #include <strstream>
    #include <iomanip.h>
    #include <iomanip.hxx>
    #include <iomanip>
  • All Standard Library names in the ANSI IOStreams library are in namespace std. Typically you would qualify each Standard Library name with std:: or put using namespace std; at the top of your source file.
    To facilitate upgrading in all but strict_ansi and strict_ansi_errors mode, using namespace std; is set by default. In strict_ansi or strict_ansi_errors modes, after including an ANSI IOStream header, you must qualify each name inside namespace std individually or do


          using namespace std; 
    

  • In the pre-ANSI IOstream library, including <iomanip.h> or <strstream.h> gave you access to cout, cin, and cerr. To access the predefined streams with the ANSI IOStreams library, make the following changes:
    change
    #include <iomanip.h>
    to
    #include <iomanip>
    #include <iostream>
    #include using namespace std;
    change
    #include <strstream.h>
    to
    #include <strstream>
    #include <iostream>
    #include using namespace std;
  • The istream::ipfx, istream::isfx, ostream::opfx, ostream::osfx do not exist in the ANSI IOStreams. Their functionality is provided by the sentry class found in basic_istream and basic_ostream, respectively.
    Common prefix code is provided by the sentry's constructor. Common suffix code is provided by the sentry's destructor. As a result, calls to ipfx(), isfx(), opfx(), and osfx() have their functionality replaced by construction and destruction of std::istream::sentry objects and std::ostream::sentry object respectively. For example:


    #include <iostream.hxx>           |  #include <iostream.hxx> 
    void func (istream &is)           |  void func (ostream &os) 
    {                                 |  { 
       if (is.ipfx())                 |     if (os.opfx()) 
           ...                        |         ... 
       is.isfx();                     |     os.osfx(); 
    }                                 |  } 
                                      | 
    Would be coded as:                |  Would be coded as: 
                                      | 
    #include <iostream>               |  #include <iostream> 
    void func (istream &is)           |  void func (ostream &os) 
    {                                 |  { 
       istream::sentry ipfx(is);      |     ostream::sentry opfx(os); 
       if (ipfx)                      |     if (opfx) 
          ...                         |        ... 
       //is.isfx(); implicit in dtor  |     //os.osfx(); implicit in dtor 
    }                                 |   } 
    

  • The following macros from the pre-ANSI <iomanip.h> are no longer available in <iomanip>:


    SMANIP, IMANIP, OMANIP, IOMANIP, 
    SAPP,   IAPP,   OAPP,   IOAPP, 
    SMANIPREF, IMANIPREF, OMANIPREF, IOMANIPREF, 
    SAPPREF, IAPPREF, OAPPREF, IOAPPREF 
    

    You can add them yourself, but their use will not be portable.

  • The streambuf::stossc() function, which advances the get pointer forward by one character in a stream buffer, is not available in the ANSI IOstream library. You can make use of the std::streambuf::sbumpc() function to move the get pointer forward one place. This function returns the character it moved past. These two functions are not exactly equivalent---if the get pointer is already beyond the end, stossc() does nothing, and sbumpc() returns EOF.


         istream &extract(istream &is) 
         { 
            ... 
            is.rdbuf()->stossc(); 
         } 
    

  • ios::bitalloc() is no longer available in the ANSI IOstream library.
  • The filebuf constructors have changed in the ANSI IOstream library. The pre-ANSI filebuf class contained three constructors:


        class filebuf : public streambuf 
        { 
           filebuf(); 
           filebuf(int fd); 
           filebuf(int fd, char * p, int len); 
           ... 
        } 
    

    In the ANSI IOstream library, filebuf is a typedef for basic_filebuf<char>, and the C++ Working Paper defines one filebuf constructor:


        basic_filebuf(); 
    

    To facilitate backward compatibility, the DIGITAL C++ ANSI IOStream library does provide basic_filebuf(int fd) as an extension. However, the use of extensions is not portable.
    For example, consider the filebuf constructors in the following pre-ANSI IOStream library program:


    #include <fstream.hxx> 
     
    int main () { 
        int fd = 1; 
        const int BUFLEN = 1024; 
        char buf [BUFLEN]; 
        filebuf fb(fd,buf,BUFLEN); 
        filebuf fb1(fd); 
        return 0; 
    } 
    

    To be strictly ANSI conforming, you would need to recode as follows:


      filebuf fb(fd,buf,BUFLEN); as filebuf fb();  and 
      filebuf fb1(fd); as filebuf fb1(); 
    

    If you want to make use of the DIGITAL C++ ANSI IOStream filebuf(fd) extension, you could recode:


      filebuf fb(fd,buf,BUFLEN); as filebuf fb(fd);  and 
      filebuf fb1(fd); as filebuf fb1(fd); 
    

  • The DIGITAL C++ ANSI IOstream library contains support for the filebuf::fd() function, which returns the file descriptor for the filebuf object and EOF if the filebuf object is closed as a nonportable extension.
    This function is not supported under the -std strict_ansi or -std strict_ansi_errors compiler modes.
  • The following functions are not defined in the ANSI IOStreams library. They are provided in the DIGITAL C++ ANSI IOstream library for backward compatibility only. Their use is not portable.


        ifstream::ifstream(int fd); 
        ifstream::ifstream(int fd, char *p, int len) 
        ofstream::ofstream(int fd); 
        ofstream::ofstream(int fd, char *p, int len); 
        fstream::fstream(int fd); 
        fstream::fstream(int fd, char *p, int len); 
    

  • The following attach functions, which attach, respectively, a filebuf, fstream, ofstream, and ifstream to a file are not available in the ANSI IOstream library:


       filebuf::attach(int); 
       fstream::attach(int); 
       ifstream::attach(int);   
       ofstream::attach(int); 
    

    If you do not want to make use of DIGITAL C++ ANSI IOstream library extensions, you must recode the use of attach as follows:
    From:


    #include <fstream.hxx>                        
    #include <stdio.h>                             
    #include <fcntl.h>                             
    int main () {                                  
        int fd;                                    
        fd = open("t27.in",O_RDWR | O_CREAT, 0644); 
        ifstream ifs;                              
        ifs.attach(fd);                            
        fd = creat("t28.out",0644);                
        ofstream of;                                
        of.attach(fd);                             
        return 0;                                  
    } 
    

    To:


    #include <fstream> 
    int main () { 
        ifstream ifs("t27.in", ios::in | ios::out); 
        ofstream ofs("t28.out"); 
        return 0; 
    } 
    

  • The ios enumerators for controlling the opening of files, ios::nocreate and ios::noreplace, are not available in the ANSI IOstream library.
  • The istream_withassign and ostream_withassign classes are not available in the ANSI IOstream library.
  • In the ANSI IOstream library ios_base::width() applies to all formatted inserters including operator << (char). This means that the stream width specified by either the manipulator setw() or the ios_base::width() member function will apply padding to the next output item even if it is a char.
    This was not the case in the pre-ANSI IOStreams library, where width() applied to all formatted inserters except the char inserter. The reasons for the change (to allow ostream::operator<<(char) to do formatting) are:
    1. It allows operator<< functions to do formatting consistently.
    2. It allows operator<<(char) and put(char) (formatted and unformatted operations on char) to have different functionality.

    Consider the following example:


    #ifdef __USE_STD_IOSTREAM 
    #   include <iostream> 
    #   include <iomanip> 
    #else 
    #   include <iostream.hxx> 
    #   include <iomanip.hxx> 
    #endif 
    int main () { 
        cout.width(10); 
        cout.fill('^'); 
        cout << 'x' << '\n'; 
        cout << '[' << setw(10) << 'x' << ']' << endl; 
        return 0; 
    } 
    

    In the ANSI IOstream library the output is:


    ^^^^^^^^^x 
    [^^^^^^^^^x] 
    

    In the pre-ANSI IOstream library the output is:


    x 
    [x]^^^^^^^^^ 
    

  • In the pre-ANSI IOstream library, printing signed char * or a unsigned char * printed the address of the string. In the ANSI IOstream library the string is printed. Consider the following example:


    #ifdef __USE_STD_IOSTREAM 
    #include <iostream> 
    #else 
    #include <iostream.hxx> 
    #endif 
     
    int main () { 
        char * cs = (char *) "Hello"; 
        signed char *ss = (signed char *) "world"; 
        unsigned char *us = (unsigned char *) "again"; 
     
        cout << cs << " " << ss << " " << us << endl; 
        return 0; 
    } 
    

    The output in the ANSI IOstream library is:


    Hello world again 
    

    The output in the pre-ANSI IOstream library is:


    Hello 0x120001748 0x120001740 
    

    To obtain output equivalent to the pre-ANSI IOStreams, you might do the following:


    cout << hex << showbase << (long) ss << " " << (long) us << endl; 
    

  • In the pre-ANSI IOstream library printing a signed char prints its integer value. In the ANSI IOstream library printing a signed char prints it as a character. Consider the following example:


    #ifdef __USE_STD_IOSTREAM 
    #include <iostream> 
    #else 
    #include <iostream.hxx> 
    #endif 
     
    int main () { 
        signed char c = (signed char) 'c'; 
        cout << c << endl; 
        return 0; 
    } 
    

    The output in the ANSI IOstream library is:


    c 
    

    The output in the pre-ANSI IOstream library is:


    99 
    

    To obtain output equivalent to the pre-ANSI IOStreams, you must do the following:


    cout << (long) c << endl; 
    

  • In the ANSI IOstream library, reading invalid floating point input (where invalid input is caused by no digits following the letter e or E and an optional sign) from a stream sets failbit to flag this error state. In the pre-ANSI IOstream library, these type of error conditions might not be detected. Consider this program fragment:


        double i; 
        cin >> i; 
        cout << cin.rdstate() << ' ' << i << endl; 
    

    On the input: 123123e
    The output in the ANSI IOstream library is:


    4 2.65261e-314          // failbit set 
    

    The output in the pre-ANSI IOstream library is:


    0 123123                // goodbit set 
    

  • In the ANSI IOstream library, reading integer input (which is truncated as the result of a conversion operation) from a stream sets failbit to flag this overflow condition. In the pre-ANSI IOStream library, these types of conditions might not be detected. Consider this program fragment:


        int i; 
        cin >> i; 
        cout << cin.rdstate() << ' ' << i << endl; 
    

    On the input: 9999999999999999
    The output in the ANSI IOstream library is:


    4  1874919423       // failbit set 
    

    The output in the pre-ANSI IOstream library is:


    0  1874919423       // goodbit set 
    

    In the ANSI IOstream library, reading -0 from a stream into an unsigned int outputs 0; this was not the case with the pre-ANSI IOstream library. Consider the following:


       unsigned int ui; 
       cin >> ui; 
       cout << cin.rdstate() << ' ' << ui << endl; 
    

    On the input: -0
    The output in the ANSI IOstream library is:


    0 0 
    

  • In the ANSI IOstream library, the istream::getline() function extracts characters and stores them into successive locations of an array whose first element is designated by s. If n-1 characters are stored, failbit is set. This was not the case in the pre-ANSI IOstream library. Consider the following:


    main() 
    { 
            char buffer[10]; 
            cin.getline (buffer,10); 
            cout << cin.rdstate() << ' ' << buffer << endl; 
            return 0; 
    } 
    

    With input of: 1234567890
    The output in the ANSI IOstream library is:


    4 123456789 
    

    The output in the pre-ANSI IOstream library is:


    0 123456789 
    

  • When printing addresses, the ANSI library does not print a leading "0x" to indicate a hexadecimal base. The pre-ANSI library did. Consider the following:


    #include <iostream> 
    main() 
    { 
    double d; 
    int i; 
            void *p = (void *) &d; 
            int *pi = &i; 
            cout << (void *) 0 << ' ' << p << ' ' pi << endl; 
    } 
    

    The output in the ANSI IOstream library is:


    0 11fffe7a0 11fffe798 
    

    The output in the pre-ANSI IOstream library is:


    0x0 0x11fffdc40 0x11fffdc38 
    

  • basic_filebuf::setbuf is a protected member function in the ANSI IOstream library. Therefore, the following will no longer compile:


    int main() { 
       filebuf fb; 
       ... 
       fb.setbuf(0,0); 
       return 0; 
    } 
    

7.5.6 Upgrading Pre-ANSI bit_vector to ANSI vector<bool>

The bit_vector class provided in the library previous to the current compiler is no longer available. The current compiler provides this functionality with the ANSI C++ vector<bool> class. For example, consider a program making use of bit_vector as follows:


 
#include <vector> 
#include <iostream.h> 
int main () { 
  bit_vector bv(3); 
  bv[0] = bv[2] = 1; bv[1] = 0; 
  bit_vector::iterator bi=bv.begin(); 
  (*bi).flip(); 
  cout << bv[0] << bv[1] << bv[2] << endl; 
  return 0; 
} 
 

This would be coded as follows using the pre-ANSI <iostream.h> header:


 
#include <vector> 
#include <iostream.h> 
using namespace std; 
int main () { 
  vector<bool> bv(3); 
  bv[0] = bv[2] = true; bv[1] = false; 
  vector<bool>::iterator bi=bv.begin(); 
  (*bi).flip(); 
  cout << (bool)bv[0] << endl; //cast vector<bool> subscript operator 
  return 0; 
} 
 

Or it would be coded as follows using the ANSI <iostream> header:


 
#define __USE_STD_IOSTREAM 
#include <vector> 
#include <iostream> 
using namespace std; 
int main () { 
  vector<bool> bv(3); 
  bv[0] = bv[2] = true; bv[1] = false; 
  vector<bool>::iterator bi=bv.begin(); 
  (*bi).flip(); 
  cout << bv[0] << bv[1] << bv[2] << endl; 
  return 0; 
} 
 


Previous Next Contents Index

   
Burgundy bar
DIGITAL Home Feedback Search Sitemap Subscribe Help
Legal