Oracle Solaris Studio 12.3 C++ FAQ

Contents

  1. New or Updated Questions For This Release
  2. Versions, Patches, and Support
  3. Compiler Compatibility
  4. Coding and Diagnostics
  5. Library Compatibility
  6. Compile-Time Performance
  7. Run-Time Performance



 

A. New or Updated Questions For This Release



 

B. Versions, Patches, and Support

  1. How can I dependably identify the C++ compiler in each new release?
     
  2. What is the difference between standard and classic I/O streams? Can you recommend text books on the subject?
     
  3. How can I tell which C++ compiler versions are compatible?
     
  4. What RogueWave libraries are "certified" for use with Sun Studio 9?
     
  5. How can I figure out which patches exist and what problems are solved in the current patches?
     
  6. Do I need to have patches to libCstd.so.1 and libCrun.so.1?
     


  1. How can I dependably identify the C++ compiler in each new release?

    Every compiler predefines some macros that identify it. Compiler vendors tend to keep these predefined macros stable from release to release, and we in particular document them as a stable public interface.

    A good way to find out what compiler you have is to write a small program that tests for predefined macros and outputs a string suitable for your intended use. You can also write a pseudo-program and compile it with -E (or the equivalent for other compilers).

    See 'macros' in the index of the C++ User's Guide for a list of predefined C++ compiler macros. In particular, the value of __SUNPRO_CC. Starting with C++ 5.10 the value is a 4-digit hex number. The first digit is the major release, the next two digits are the minor release, the fourth is the micro release. Example: C++ 5.12 is 0x5120.

    For earlier releases 5.0 through 5.9, __SUNPRO_CC is a three-digit hex number. The first digit is the major release. The second digit is the minor release. The third digit is the micro release. For example, C++ 5.9 is 0x590.

    For any two releases, the value of __SUNPRO_CC is greater in the later release. To determine the exact release, you must first test for less than 0x5100 for releases prior to 5.10, then you can unpack the 3- or 4-digit value.

    Here are predefined macros of interest:

     
    #ifdef __sun 
           Oracle Solaris or other SunOS derived operating system 
    #endif 
    #ifdef __SUNPRO_C 
           Oracle Solaris Studio C compiler /* __SUNPRO_C value is the version 
    number */ 
    #endif 
    #ifdef __SUNPRO_CC 
           Oracle Solaris Studio C++ compiler /* __SUNPRO_CC value is the version 
    number */ 
    #endif 
    #ifdef __sparc 
           generate code for SPARC (R) architecture (32-bit or 64-bit) 
    #endif 
    #ifdef __sparcv9 
           generate code for 64-bit SPARC architecture 
    #endif 
    #ifdef __i386 
           generate code for 32-bit x86 architecture 
    #endif 
    #ifdef __amd64 
           generate code for 64-bit x64 architecture 
    #endif

     

  2. What is the difference between standard and classic I/O streams? Can you recommend text books on the subject?

    The design and implementation of the two libraries are entirely different. The programming interface for simple I/O is quite similar. For more complex operations, such as writing your own stream classes or manipulators, it is quite different.

    The classic iostream library in this version is compatible with the version shipped with C++ 3.x and 4.x. In addition to the documentation provided with this release, here is a reference book:

    • Steve Teale
      C++ IOStreams Handbook
      Addison-Wesley 1993

    The standard iostream library is described by the C++ Standard. In addition to the documentation provided with this release, here are two good references:

    • Nicolai Josuttis
      The C++ Standard Library
      Addison-Wesley 1999
      (A tutorial on the entire C++ standard library)

    • Angelika Langer and Klaus Kreft
      Standard C++ IOStreams and Locales
      Addison-Wesley 1999
      (A tutorial on just iostreams and locales.)

    Source code for implementing simple I/O looks the same for both versions of iostreams. To ease the transition, we provide the non-standard headers <iostream.h>, <fstream.h>, and <strstream.h> for standard iostreams. They provide a similar set of declarations in the global namespace as are found in classic iostreams. If you use these headers, you will get the standard iostreams by default. To get classic iostreams, you should compile and link with -library=iostream.

    For example, the following code works with both classic and standard iostreams using our compiler, although not with all compilers.

    #include <iostream.h>
    
    class myclass {
    public:
            myclass(int i) : k(i) { }
            friend ostream& operator<<(ostream&, const myclass&);
    private:
            int k;
    };
    
    // user-written output operator
    ostream& operator<<(ostream& os, const myclass& m)
    {
        os << m.k;
        return os;
    }
    
    int main()
    {
        // simple I/O using cout, cin
        cout << "Enter a number: " << endl;
        int val;
        if( ! (cin >> val) ) {
            cout << "Invalid entry, using zero" << endl;
            val = 0;
        }
    
        // using the user-written output operator
        myclass m(val);
        cout << "Value is " << m << endl;
    }
    

    This code compiles and runs using Solaris Studio compilers in any of these ways:

    example% CC example.cc # standard mode with standard iostreams
    example% CC -library=iostream example.cc # standard mode with classic iostreams
    
    
    
  3. How can I tell which C++ compiler versions are compatible?

    First, a definition: "Upward compatible" means that object code compiled with an older compiler can be linked with code from a later compiler, as long as the compiler that is used in the final link is the latest compiler in the mix.

    The C++ 4.0, 4.1, and 4.2 compilers are upward compatible. (There are some "name mangling" issues among the compiler versions that are documented in the C++ 4.2 manuals.)

    The 5.0 throug 5.11 compilers are upward compatible with the 4.2 compiler in compatibility mode (-compat) . The actual object code from the 4.2 compiler is fully compatible with the object code from the current version through version 5.0, but debugging information (stabs) emitted by later compilers is not compatible with earlier debuggers.

    Beginning with C++ 5.12, compatibility mode is no longer available.

    Code compiled in the default standard mode by the current C++ compiler through version 5.0 are upward compatible. The actual object code is fully compatible, but debugging information (stabs) emitted by later compilers is not compatible with earlier debuggers.

  4. What RogueWave libraries are "certified" for use with Sun Studio 9?

    We cannot reliably track which vendors have certified which versions of their products for use with which versions of our compilers. And making sure this FAQ is always up to date would be harder still. You have to check with the vendor to find out whether they have tested their product with any particular version of the C++ compiler.

    However, some RogueWave libraries ship with our compilers, and we implicitly certify that the versions we ship work together.

  5. How can I figure out which patches exist and what problems are solved in the current patches?

    For the most up-to-date information on product patches, check the Solaris Studio pages on the Oracle Technical Network (OTN) .

  6. Do I need to have patches to libCstd.so.1 and libCrun.so.1?

    Typically, the Solaris operating system ships with the most recent versions of these libraries. However, due to bug fixes and some performance improvements, there are often patches to these libraries. These patches are always cumulative and always backward compatible.



 

C. Compiler Compatibility

  1. I recently patched my Solaris Operating System and now my code won't compile. What happened?
     
  2. How do I mix C++ or C programs with F77, F90, or F95 programs?
     


  1. I recently patched my Solaris OS and now my code won't compile. What happened?

    New math functions available in recent Solaris versions can cause previously valid code to become invalid.

    The functions in <math.h> previously had versions only for type double. The new Solaris headers and library have overloads for types float and long double as well. To avoid an ambiguous call you might need to add explicit casts when calling these functions with integer arguments. For example:

    #include <math.h>
    extern int x;
    double      z1 = sin(x); // now ambiguous
    double      z2 = sin( (double)x ); // OK
    float       z3 = sin( (float)x ); // OK
    long double z4 = sin( (long double)x ); //  OK

    The Solaris patches listed below provide full ANSI C++ <cmath> and <math.h> library support as implemented in the libm patch for Solaris 8 and 9.

    • Solaris 9 sparc (PatchId 111722-04)
    • Solaris 9 i386 (PatchId 111728-03)
    • Solaris 8 sparc (PatchId 111721-04)
    • Solaris 8 i386 (PatchId 112757-01)

     

  2. How do I mix C++ or C programs with F77, F90, or F95 programs?

    You can use the -xlang={f90|f95|f77} option. This option tells the driver to figure out exactly which libraries need to be on the link line and to figure out the order in which they need to appear.

    The -xlang option is not available for the C compiler. To mix C and Fortran routines, you must compile them with cc and link them using the Fortran linker.



 

D. Coding and Diagnostics

  1. Why do I get errors and warnings involving file foo.cc when I'm not compiling or including foo.cc in my program?
     
  2. Why do I get "duplicate definition" error messages when I compile the foo.i file that is generated from the -P preprocessing option?
     
  3. Why am I getting an error when I link a SPARC V9 archive library into a dynamic library? It worked in Sun Studio 8.
     
  4. What causes this message: "SunWS_cache: Error: Lock attempt failed for SunWS_cache"?
     
  5. Why do I get the following warning from the linker: "ld: warning: symbol 'clog' has differing types"


  6. Why does the compiler now say that a call to abs() is ambiguous?
     
  7. When do temporary objects get destroyed?
     
  8. Why does the compiler report an ambiguity for the standard exception class?
     
  9. Why does C++ 5.3 and later emit errors about throw specifications on my derived virtual functions?
     
  10. Why do template instances turn up missing when I link my program? The instances seem to be in the template cache.
     
  11. Why do I get a warning about a function not being expanded when I use +w2 and not when I use +w2 +d?
     
  12. Why does fprintf("%s",NULL) cause a segmentation fault?
     
  13. Depending on how I call sqrt(), I get different signs for the imaginary part of the square root of a complex number. What's the reason for this?
     
  14. A friend function in a class template does not get instantiated and I get link-time errors. This worked with C++ 5.0, why doesn't it work now?
     
  15. What causes the "pure virtual function call" message at run time?
     
  16. Why does the compiler say that a derived-class virtual function hides a base-class virtual function with a different signature? My other compiler doesn't complain about the code.
     


  1. Why do I get errors and warnings involving file foo.cc when I'm not compiling or including foo.cc in my program?

    If a header file foo.h has template declarations, the compiler by default searches for a file foo with a C++ file extension (foo.c, foo.cc, foo.C, foo.cpp, foo.c++) and includes it automatically if it is found. Refer to the C++ User's Guide section titled "Template Definitions Searching" for details.

    If you have a file foo.cc that you don't intend to be treated this way, you have two options:

    • Change the name of the .h or the .cc file to eliminate the name match.
    • Disable the automatic search for template definition files by specifying the -template=no%extdef option. However, that option disables all searches for separate template definitions. You must then include all template definitions explicitly in your code so you cannot use the definitions-separate model.

      Refer to the C++ User's Guide sections 5.2.1 and 5.2.2 for further discussion of the template definitions model or refer to the index of the C++ User's Guide for pointers to descriptions of the definitions separate and definitions included models.

     

  2. Why do I get "duplicate definition" error messages when I compile the foo.i file that is generated from the -P preprocessing option?

    See the previous answer above.

    For the case where you want to compile a .i file, just rename the file to give it a unique name. Then you don't have to disable separate template compilation. For example:

            CC -P foo.cc
            mv foo.i foo_prep.i
            CC -c foo_prep.i

     

  3. Why am I getting an error when I link a SPARC V9 archive library into a dynamic library? It worked in Sun Studio 8.

    The default compiler-address code-model for V9 is -xcode=abs44, which improves performance over the previous -xcode=abs64. However, this code model is not usable within dynamic libraries. There are two solutions to the problem.

    • Recompile the object files with -xcode=pic13 or -xcode=32. This method is preferred, and nearly always the right thing.

    • Recompile the object files with -xcode=abs64. This method results in dynamic libraries that are not sharable. Each process must rewrite the library as it is copied into separate areas of memory. The method is useful for applications that run for a very long time under tight performance constraints and low system sharing.

       

  4. What causes this message: "SunWS_cache: Error: Lock attempt failed for SunWS_cache"?

    There are two main causes for the "lock attempt failed" error message about the template cache:

    • Sometimes a compilation aborts or is killed in such a way that it does not release the lock it is holding on the cache. This situation could occur in old compiler versions. Newer versions and current patches to older compilers ensure that the lock is released no matter how the compiler exits. You could remove just the lock file, but the cache is probably corrupted, and will cause further problems. The safest fix is to delete the entire template cache.

    • The template cache must be writable by the compiler process. Refer to the umask(1) man page for more information. In particular, you must be sure that the umask of a process that creates the cache or files in it allows writing by other processes that need to access the same cache. If the directory is mounted on an NFS file system, the system must be mounted for read/write.

      Unless you have a specific reason for wanting to use the -instances=extern model, we recommend using the default -instances=global model. The template cache is a frequent source of hard-to-find build problems. Delete all template caches, remove -instances=extern from all command lines, and rebuild the project. Building should be faster, with fewer problems.

  5. Why do I get the following warning from the linker: "ld: warning: symbol 'clog' has differing types"?

    The linker warns about the pair of weak symbols that have different types when you link libm.so.2 and the classic iostream library in the same program. You can ignore the warning.

    Beginning with Solaris 10, the default math library is libm.so.2, and it contains the complex log function clog in the global namespace as required by the C99 standard. If you use C++ classic iostreams by specifying -library=iostream, you get the buffered standard error stream 'clog' in the global namespace. (Standard iostreams does not have this conflicting symbol.)

    We have adjusted headers and libraries to silently rename each of these 'clog' symbols so that you can use both in one program. However, we must retain the original symbol spellings as weak symbols in each of the libraries, so that old binaries looking for the original symbols can continue to link.

    Be sure to get iostream and math declarations by including the appropriate system headers rather than declaring any of these entities yourself.

  6. Why does the compiler now say that a call to abs() is ambiguous?

    The C++ Standard in section 26.5 requires the following overloads of the abs function:

    • In <stdlib.h> and <cstdlib>

      int  abs(int);
      long abs(long);

       

    • <math.h> and <cmath>

      float       abs(float);
      double      abs(double);
      long double abs(long double);

       

    Until some updates of Solaris 8, the only version of abs available on Solaris was the traditional int version. If you invoked abs with any numeric type, the value was implicitly converted to type int, and the int version of abs was called, assuming that you included <stdlib.h> or <cstdlib>.

    Solaris headers and libraries now comply with the C++ standard regarding math functions.

    If you include, for example, <math.h> but not <stdlib.h>, and invoke abs with an integer argument, the compiler must choose among the three floating-point versions of the functions. An integer value can be converted to any of the floating-point types, and neither conversion is preferred over the others. Reference: C++ standard section 13.3.3. The function call is therefore ambiguous. You will get an ambiguity error using any compiler that conforms to the C++ Standard.

    If you invoke the abs function with integer arguments, you should include standard header <stdlib.h> or <cstdlib> to be sure you get the correct declarations for it. If you invoke abs with floating-point values, you should also include <math.h> or <cmath>.

    Here's a simple recommended programming practice: if you include <math.h> or <cmath>, also include <stdlib.h> or <cstdlib>.

    Similar considerations apply to other math functions, like cos or sqrt. Solaris headers and libraries now comply with the C++ Standard, supplying float, double, and long double overloaded versions of the functions. If you invoke, for example, sqrt with an integer value, the code formerly compiled because only one version of sqrt was available. With three floating-point versions available, you must cast the integer value to the floating-point type that you want.

            double root_2 = sqrt(2); // error
            double root_2 = sqrt(2.0); // OK
            double x = sqrt(int_value); // error
            double x = sqrt(double(int_value)); // OK

     

  7. When do temporary objects get destroyed?

    The compiler creates a temporary object sometimes for convenience, and sometimes because the language rules require it. For example, a value returned by a function is a temporary object, and the result of a type conversion is a temporary object.

    The original C++ rule was that the temporary object ("temp") could be destroyed at any time up until the end of the block in which it was created. Sun C++ compilers prior to C++ 5.9 destroyed temps at the end of the block (closing right brace).

    The rule in the C++ standard is that temps are destroyed at the end of the complete expression in which the temp is created. Usually that is at the end of the statement in which the expression appears. Beginning with C++ 5.9, the compiler follows this rule by default.

    If you find that your program depends (perhaps unintentionally) on temps living until the end of the block, you can use the option -features=no%tmplife to restore the old compiler behavior. Portable code should not depend on the old rule for lifetimes of temporaries, since few other compilers have the old behavior, even as an option.

  8. Why does the compiler report an ambiguity for the standard exception class?

    On Solaris, standard header <math.h> has a declaration for a struct "exception", as required by standard Unix. If you bring the C++ standard exception class into global scope with a using-declaration or using-directive, it creates a conflict.

    // Example 1
    
    #include <math.h>
    
    #include <exception>
    using namespace std; // using-declaration
    exception E;  // error, exception is ambiguous
    
    // Example 2:
    
    #include <math.h>
    #include <exception>
    using std::exception; // using-directive
    exception E;  // error, multiple declaration for exception

    Name resolution is slightly different for using-declarations compared to using-directives, so the error messages are not quite the same.

    Workarounds:

    • Use <cmath> instead of <math.h>. On Solaris, <cmath> contains only the declarations specified by the C and C++ standards. If you need Unix-specific features of <math.h>, you can't use this workaround.

    • Don't write using std::exception; when you also use <math.h>. Write std::exception explicitly, or use a typedef, to access the standard exception class as in this example:

      #include <math.h>
      #include <exception>
      std::exception E; // OK
      typedef std::exception stdException; // OK
      stdException F; // OK
    • Don't write using namespace std;.
      The C++ namespace std contains so many names that you are likely to have conflicts with application code or third-party libraries when you use this directive in real-world code. (Books and articles about C++ programming sometimes have this using-directive to reduce the size of small examples.) Use individual using-declarations or explicitly qualify names.

     

  9. Why does C++ 5.3 and later emit errors about throw specifications on my derived virtual functions?

    A C++ rule enforced by the C++ compiler since version 5.3 is that a virtual function in a derived class can allow only the exceptions that are allowed by the function it overrides. The overriding function can be more restrictive, but not less restrictive. Consider the following example:

    class Base {
    public:
            // might throw an int exception, but no others
            virtual void f() throw(int);
    };
    class Der1 : public Base {
    public:
            virtual void f() throw(int); // ok, same specification
    };
    class Der2 : public Base {
    public:
            virtual void f() throw(); // ok, more restrictive
    };
    class Der3 : public Base {
    public:
            virtual void f() throw(int, long); // error, can't allow long
    };
    class Der4 : public Base {
    public:
            virtual void f() throw(char*); // error, can't allow char*
    };
    class Der5 : public Base {
    public:
            virtual void f(); // error, allows any exception
    };

    This code shows the reason for the C++ rule:

    #include "base.h" // declares class Base
    void foo(Base* bp) throw()
    {
        try {
           bp->f();
        }
        catch(int) {
        }
    }

    Since Base::f() is declared to throw only an int exception, function foo can catch int exceptions, and declare that it allows no exceptions to escape. Suppose someone later declared class Der5, where the overriding function could throw any exception, and passed a Der5 pointer to foo. Function foo would become invalid, even though nothing is wrong with the code visible when function foo is compiled.

  10. Why do template instances turn up missing when I link my program? The instances seem to be in the template cache.
     

    Starting with C++ 5.5, the compiler does not use a template cache by default. Therefore we recommend that when you upgrade to C++ 5.5 or newer, you recompile your code by specifying -instances=global in order to use the default template compilation model. Therefore, when you upgrade your compiler, you remove all -instances=extern options and recompile your code in order to use the default template compilation model -instances=global.

    The template cache maintains a list of dependencies between the object files that the compiler generates, and the template instances in the cache. Note, however, that the compiler now only uses the template cache when you specify -instances=extern. If you move or rename object files, or combine object files into a library, you lose the connection to the cache. Here are two alternatives:

    • The link lines also need -instances=extern.

    • Generate object files directly into the final directory. The template cache will be in that same directory.

      Do not do this:

      example% CC -c -instances=extern f1.cc
      example% mv f1.o /new/location/for/files

      Do this instead:

      example% CC -c -instances=extern f1.cc -o /new/location/for/files/f1.o

      You can encapsulate the process in makefile macros.

    • You can create intermediate archive (.a) files using CC -xar. Each archive then contains all the template instances used by the objects in the archive. You then link those archives into the final program. Some template instances are duplicated in different archives, but the linker keeps only one of each.

       

      example% CC -c -instances=extern f1.cc f2.cc f3.cc
      example% CC -xar f1.o f2.o f3.o -o temp1.a
      example% CC -c -instances=extern f4.cc f5.cc f6.cc
      example% CC -xar f4.o f5.0 f6.0 -o temp2.a
      example% CC -c -instances=extern main.cc
      example% CC main.o temp1.a temp2.a -o main
  11. Why do I get a warning about a function not being expanded when I use +w2 and not when I use +w2 +d?

    The C++ compiler has two kinds of inlining: C++ inline function inlining, which is done by the parser, and optimization inlining, which is done by the code generator. The C and Fortran compilers have only optimization inlining. (The same code generator is used for all compilers on a platform.)

    The C++ compiler's parser attempts to expand inline any function that is declared implicitly or explicitly as inline. If the function is too large, the parser emits a warning only when you use the +w2 option. The +d option prevents the parser from attempting to inline any function. This is why the warning disappears when you use +d. (The -g option also turns off the inlining of C++ inline functions.) The -xO options do not affect this type of inlining.

    The optimization inlining does not depend on the programming language. When you select an optimization level of -xO4 or higher, the code generator examines all functions, independent of how they were declared in source code, and replaces function calls with inline code wherever it thinks the replacement will be beneficial. No messages are emitted about optimization inlining (or its failure to inline functions). The +d option does not affect optimization inlining.

  12. Why does fprintf("%s",NULL) cause a segmentation fault?

    Some applications erroneously assume that a null character pointer should be treated the same as a pointer to a null string. A segmentation violation occurs in these applications when a null character pointer is accessed.

    There are several reasons for not having the *printf() family of functions check for null pointers. These include, but are not limited to the following reasons:

    • Doing so provides a false sense of security. It makes programmers think that passing null pointers to printf() is OK.
    • It encourages programmers to write non-portable code. ANSI C, XPG3, XPG4, SVID2, and SVID3 say that printf("%s", pointer) needs to have pointer point to a null terminated array of characters.
    • It makes debugging harder. If the programmer passes a null pointer to printf() and the program drops core, it is easy to use a debugger to find which printf() call gave the bad pointer. However, if printf() hid the bug by printing "(null pointer)," then other programs in a pipeline are likely to try interpreting "(null pointer)" when they are expecting some real data. At that point it may be impossible to determine where the real problem is hidden.

    If you have an application that passes null pointers to *printf, you can use a special shared object on Solaris /usr/lib/0@0.so.1 that provides a mechanism for establishing a value of 0 at location 0. Because this library masks all errors involving the dereference of a null pointer of any type, you should use this library only as a temporary workaround until you can correct the code.

  13. Depending on how I call sqrt(), I get different signs for the imaginary part of the square root of a complex number. What's the reason for this?

    The implementation of this function is aligned with the C99 csqrt Annex G specification. For example, here's the output from the following code example :

    complex sqrt (3.87267e-17, 0.632456)
    	float sqrt(3.87267e-17, -0.632456)
    • Example using libcomplex in compatibility mode:

      #include <iostream.h>
      #include <math.h>
      #include <complex.h>
       
      int main ()
      {
            complex ctemp(-0.4,0.0);
            complex c1(1.0,0.0);
            double  dtemp(-0.4);
            cout<< "complex sqrt "<< sqrt(ctemp)<<endl;
            cout<< "float sqrt   "<< sqrt(c1*dtemp)<<endl;
      }
      
    • Example using libCstd in standard mode:

      #include <iostream>
      #include <math.h>
      #include <complex>
      
       
      using namespace std;
       
      int main ()
      {
           complex<double> ctemp(-0.4,0.0);
           complex<double> c1(1.0,0.0);
           double  dtemp(-0.4);
           cout<< "complex sqrt "<< sqrt(ctemp)<<endl;
           cout<< "float sqrt   "<< sqrt(c1*dtemp)<<endl;
      }
      

    The sqrt function for complex is implemented using atan2. The following example illustrates the problem by using atan2. The output of this program is:

    c=-0.000000  b=-0.400000  atan2(c, b)=-3.141593
    a=0.000000  b=-0.400000  atan2(a, b)=3.141593

    In one case, the output of atan2 is negative and in the other case it's positive. It depends on whether -0.0 or 0.0 gets passed as the first argument.

    #include <stdio.h>
    
    #include <math.h>
     
    int main()
    {
        double a = 0.0;
        double b = -0.4;
        double c = a*b;
        double d = atan2(c, b);
        double e = atan2(a, b);
        printf("c=%f  b=%f  atan2(c, b)=%f\n", c, b, d);
        printf("a=%f  b=%f  atan2(a, b)=%f\n", a, b, e);
    }
  14. What causes the "pure virtual function call" message at run time?

    A "pure virtual function called" message always arises because of an error in the program. The error occurs in either of the following two ways:

    • You can cause this error by passing the "this" parameter from a constructor or destructor of an abstract class to an outside function. During construction and destruction, "this" has the type of the constructor's or destructor's own class, not the type of the class ultimately being constructed. You can then wind up trying to call a pure virtual function. Consider the following example:

      class Abstract;
      
      void f(Abstract*);
      
      class Abstract {
      public:
              virtual void m() = 0; // pure virtual function
              Abstract() { f(this); }   // constructor passes "this"
      };
      
      void f(Abstract* p)
      {
              p->m();
      }

      When f is called from the Abstract constructor, "this" has the type "Abstract*", and function f attempts to call the pure virtual function m.

    • You can also cause this error by trying to call a pure virtual function that has been defined without using explicit qualification. You can provide a body for a pure virtual function, but it can be called only by qualifying the name at the point of the call, bypassing the virtual-call mechanism.

      class Abstract {
      public:
              virtual void m() = 0; // body provided later
              void g();
      };
      
      void Abstract::m() { ... } // definition of m
      
      void Abstract::g()
      {
              m(); // error, tries to call pure virtual m
              Abstract::m(); // OK, call is fully qualified
      }
  15. Why does the compiler say that a derived-class virtual function hides a base-class virtual function with a different signature? My other compiler doesn't complain about the code.

    The C++ rule is that overloading occurs only within one scope, never across scopes. A base class is considered to be in a scope that surrounds the scope of a derived class. Any name declared in a derived class therefore hides, and cannot overload, any function in a base class. This fundamental C++ rule predates the ARM.

    If another compiler does not complain, it is doing you a disservice, because the code will not behave as you probably expect. Our compiler issues a warning while accepting the code. (The code is legal, but probably does not do what you want.)

    If you wish to include base-class functions in an overloaded set, you must do something to bring the base-class functions into the current scope. You can add a using-declaration:

    class Base {
    public:
            virtual int    foo(int);
            virtual double foo(double);
    };
    
    class Derived : public Base {
    public:
            using Base::foo; // add base-class functions to overload set
            virtual double foo(double); // override base-class version
    };


 

E. Library Compatibility

  1. What library configuration macros can I modify to get different features from the C++ compiler runtime libraries?
     
  2. When do I need to use -I and -L options?
     
  3. How do I get a C++ standard library (stdlib) that is fully compliant? What functionality does the current libCstd not support?
     
  4. What standard library functionality is missing from libCstd?
     
  5. What are the consequences of the missing standard library functionality?
     
     

  1. What library configuration macros can I modify to get different features from the C++ compiler runtime libraries?

    Do not attempt to define, undefine, or modify any of the library configuration macros. The library headers must match the way the libraries were built. Otherwise, your program might not compile, might not link, and probably will not run correctly.

  2. When do I need to use -I and -L options?

    Specify the -I option to point to directories that contain your project header files when these header files are not in the same directory as the files that include them, or to point to directories that contain header files for third-party libraries that you acquire. Specify the -L options to point to directories that contain libraries that you build, or to third-party libraries that you acquire.

    Never use -I to point into /usr/include or into the compiler installation area. Never use -L to point into /lib, /usr/lib, or into the compiler installation area. The CC compiler driver knows the location of the system headers and libraries and follows the correct search order. You can cause the compiler to find the wrong headers or libraries by using -I or -L options that point into system directories.

  3. How do I get a C++ standard library (stdlib) that is fully compliant? What functionality does the current libCstd not support?

    The default library, libCstd, is forward and backward compatible with all of the C++ compilers from 5.0 through 5.12. It is not very standard-conforming, however (see the following questions). If you need better conformance to the C++ standard but do not need compatibility with libCstd, you have these options:

    1. Use the supplied STLport library. This library has good conformance to the C++ standard, except that it lacks support for locales (for use in I18N and L10N programming). To use this library, recompile the entire program, including any C++ libraries that are linked to it, using the option -library=stlport4 on every CC command line. Be sure to link the program with CC, not directly with ld.

    2. On Solaris 10 update 10 or Solaris 11, you can use the Apache stdcxx library which is very standard-conforming, including support for locales. To use this library, recompile the entire program, including any C++ libraries that are linked to it, using the option -library=stdcxx4 on every CC command line. Be sure to link the program with CC, not directly with ld.

    3. On Linux and on Solaris/x86, you can compile in g++ compatibility mode and use the g++ runtime library libstdc++. Recompile the entire program, including any C++ libraries that are linked to it, using the option -compat=g on every CC command line. Be sure to link the program with CC, not directly with ld. (Note: We have not evaluated libstdc++ for standards conformance.)

  4. What standard library functionality is missing from libCstd?

    The standard library was originally (in C++ 5.0) built without support for features which required member template and partial specialization in the compiler. Although these features have been available since C++ 5.1, they cannot be turned on in the standard library because they would compromise backward compatibilitiy. The following is a list of missing functionality for each disabled feature.

    In <algorithm>, the following template functions (non-member) are not supported:

    count(), count_if()

    In <iterator>, the following templates are not supported:

    template <class Iterator> struct iterator_traits {}
    template <class T> struct iterator_traits<T*> {}
    template <class T> struct iterator_traits<const T*>{}
    template typename iterator_traits::difference_type distance(InputIterator first, InputIterator last);

    • Disabled feature: member template functions

      • In class complex in <complex>:

        template <class X> complex<T>& operator= (const complex<X>& rhs)
        template <class X> complex<T>& operator+= (const complex<X>& rhs)
        template <class X> complex<T>& operator-= (const complex<X>& rhs)
        template <class X> complex<T>& operator*= (const complex<X>& rhs)
        template <class X> complex<T>& operator/= (const complex<X>&)
      • In class pair in <utility>:

        template<class U, class V> pair(const pair<U, V> &p);

      • In class locale in <locale>:

        template <class Facet> locale combine(const locale& other);

      • In class auto_Ptr in <memory>:

        auto_ptr(auto_ptr<Y>&);
        auto_ptr<Y>& operator =(auto_ptr<Y>&);
        template <class Y> operator auto_ptr_ref<Y>();
        template <class Y> operator auto_ptr<Y>();

      • In class list in <list>:

        Member template sort.

      • In most template classes:

        Template constructors.

    • Disabled feature: member template classes

      In class auto_ptr in <memory>:

      template <class Y> class auto_ptr_ref{};
      auto_ptr(auto_ptr(ref<X>&);

    • Disabled feature: overloading of function template arguments that are partial specializations

      In <deque>, <map>, <set>, <string>, <vector> and <iterator> the following template functions (non-member) are not supported:

      • For classes map, multimap, set, multiset, basic_string, vector, reverse_iterator, and istream_iterator:

        bool operator!= ()

      • For classes map, multimap, set, multiset, basic_string, vector and reverse_iterator:

        bool operator> ()
        bool operator>= ()
        bool operator<= ()

      • For classes map, multimap, set, multiset, basic_string, and vector:

        void swap()

    • Disabled feature: partial specialization of template classes with default parameters

  5. What are the consequences of the missing standard library functionality?

    Some code that is valid according to the C++ standard will not compile.

    The most common example is creating maps where the first element of the pair could be const but isn't declared that way. The member constructor template would convert pair<T, U> to pair<const T, U> implicitly when needed. Because that constructor is missing, you get compilation errors instead.

    Since you are not allowed to change the first member of a pair in a map anyway, the simplest fix is to use an explicit const when creating the pair type. For example, instead of pair<int, T> use pair<const int, T>; instead of map<int, T> use map<const int, T>.



 

F. Compile-Time Performance  

  1. How come I'm not seeing an improvement in compile time even though I've started using the precompiled header facility of the C++ compiler?
     
  2. Why does a large file take so much longer to compile than a shorter one?
     
  3. Since upgrading to C++ 5.10, the size of executable files with debug data is huge.
     
  4. Can a single compilation process be distributed onto multiple processors? More generally, does a multiprocessor (MP) system always have better compile-time performance?
     


 

  1. How come I'm not seeing an improvement in compile time even though I've started using the precompiled header facility of the C++ compiler?

    Using precompiled headers does not guarantee faster compile times. Precompiled headers impose some overhead that is not present when you compile files directly. To gain a performance advantage, the precompiled headers must have some redundancy that precompilation can eliminate.

    For example, a program that is highly likely to benefit from precompilation is one that includes many system headers, iostreams, STL headers, and project headers. Those files contain conditionally-compiled code. Some headers are included multiple times, and the compiler must scan over the entire file if only to discover there is nothing to do in the redundant includes. System headers typically have hundreds of macros to expand.

    Using a precompiled header means opening one file instead of dozens. The multiple includes that do nothing are eliminated, as are comments and extra white space. The macros in the headers are pre-expanded. Typically, these savings add up to a significant reduction in compile time.

  2. Why does a large file take so much longer to compile than a shorter one?

    The size of the file is probably not the issue so here are three likely causes for the delay.

    • The size of functions in the file and the level of optimization

      Large functions at high optimizations take a long time to process, and can require lots of memory. If the code uses large macros extensively, a function that looks small might become very large after macro expansion.

      Try compiling without any optimization (no -xO? or -O? option). If the compilation completes quickly, the problem is probably one or more very large functions in the file, and the time and memory necessary to optimize it.

      In addition, make sure the computer used for compilation has plenty of physical memory for the compilation run. If you don't have enough memory, the optimization phase can cause thrashing.

    • Inline functions

      Inline functions (in C and C++) act like macros where compilation time is concerned. When a function call is expanded inline, it can turn into a lot of code. The compiler then is dealing with one large function instead of 2 or more small functions.

      Compilations often proceed more quickly when you disable function inlining. Of course, the resulting code will probably run more slowly.

      See the description of -xinline and "Using Inline Functions" in the C++ User's Guide for more information.

    • C++ class templates

      C++ templates cause the compiler to generate code based on the templates invoked. One line of source code can require the compiler to generate one or more template functions. It's not that templates themselves slow down compilation significantly, but that the compiler has more code to process than is apparent by looking at the original source code.

      For example, if it were not for the standard library already having the functions, this line of code

      cout << "value = " << x << endl;

      would cause the compiler to generate 241 functions.

     

  3. Since upgrading to C++ 5.10, the size of executable files with debug data is huge.

    Prior to C++ 5.10, the compiler emitted debug data in "stabs" format by default. Stabs are kept in the individual .o files, and are not copied into the executable program. The program has a small set of "index stabs" that point to the .o files containing the debug data. To debug a program, the .o files must be available, and in the same location as when the program was built.

    Beginning with C++ 5.10, debug data is emitted in the industry-standard "dwarf" format. Dwarf format does not allow the separation of debug data from the executable program, so all the debug data is copied into the executable. As a result, you don't need to have .o files to debug the program.

    You can see a similar effect with stabs, by building with the -xs option. All stabs data is copied into the executable program. You should find that the executable is similar in size when using dwarf as when using stabs and -xs. Beginning with C++ 5.11, stabs data is not fully supported.

  4. Can a single compilation process be distributed onto multiple processors? More generally, does a multiprocessor (MP) system always have better compile-time performance?

    The compiler itself is not multithreaded. You can expect better performance with MP systems, because the computer always has many other processes running at the same time as any one compilation.

    If you use dmake (one of the tools that ships with the compiler), you can run multiple compilations simultaneously.

    See also the -xipo option in the C++ Users Guide. When optimizing across multiple object files, multiple copies of the code generator can run at the same time, if the computer has sufficient resources.



 

G. Run-Time Performance

  1. Standard library streams are slower than gcc streams. This is a performance hit for me. Is there a solution in sight?
     
  2. Does C++ always inline functions marked with "inline" keyword? Why didn't I see functions inlined even though I wrote them that way?
     


  1. Standard library streams are slower than gcc streams. This is a performance hit for me. Is there a solution in sight?

    You can either specify C++ compiler option -sync_stdio=no at link time to fix this problem or add a call to the sync_with_stdio(false) function and recompile.

    The major performance problem with stdlib 2.1.1 is that it synchronizes C stdio with C++ streams by default. Each output to cout is flushed immediately. If your program does a lot of output to cout but not to stdout, the excess buffer flushing can add significantly to the run-time performance of the program. The C++ standard requires this behavior, but not all implementations meet the standard. The following program demonstrates the synchronization problem. It must print "Hello beautiful world" followed by a newline:

        #include <iostream>
        #include <stdio.h>
        int main()
        {
            std::cout << "Hello ";
            printf("beautiful ");
            std::cout << "world";
            printf("\n");
        }
    

    If cout and stdout are independently buffered, the output could be scrambled.

     

    If you cannot recompile the executable, specify the new C++ compiler option -sync_stdio=no at link time. This option causes sync_with_stdio( ) to be called at program initialization before any program output can occur.

    If you can recompile, add a call to the sync_with_stdio(false) function before any program output thereby specifying that the output does not need to be synchronized. Here is a sample call:

            #include <iostream>
            int main(int argc, char** argv)
            {
                    std::ios::sync_with_stdio(false);
            }

    The call to sync_with_stdio should be the first one in your program.

    See the C++ User's Guide or the C++ man page CC(1) for more information on -sync_stdio.

  2. Does C++ always inline functions marked with inline keyword? Why didn't I see functions inlined even though I wrote them that way?

    Fundamentally, the compiler treats the inline declaration as a guidance and attempts to inline the function. However, there are still cases where it will not succeed. The restrictions are:

    • Some rarely executed function calls are not expanded. This change helps achieve a better balance of compilation speed, output code size, and run-time speed.

      For example, expressions used in static variable initialization are only executed once and thus function calls in those expressions are not expanded. Note that the inline function func might not be expanded when called in an initialization expression of static variables, it could still be inlined in other places. Similarly, function calls in exception handlers might not be expanded, because those code is rarely executed.

    • Recursive functions are inlined only to the first call level. The compiler cannot inline recursive function calls indefinitely. The current implementation stops at the first call to any function that is being inlined.  

    • Sometimes even calls to small functions are not inlined. The reason for this is that the total expanded size may be too large. For example, func1 calls func2, and func2 calls func3, and so forth. Even if each of these functions is small and there are no recursive calls, the combined expanded size could be too large for the compiler to expand all of them.

      Many standard template functions are small, but have deep call chains. In those cases, only a few levels of calls are expanded.

    • C++ inline functions that contain goto statements, loops, and try/catch statements are not inlined by the compiler. However, they might be inlined by the optimizer at the -xO4 level.  

    • The compiler does not inline large functions. Both the compiler and the optimizer of the C++ compiler place a limit on the size of inlined functions. This limitation is our general recommendation. For special cases, please consult with technical support to learn about the internal options that raise or lower this size limitation.  

    • A virtual function cannot be inlined, even though it is never redefined in subclasses. The reason is that the compiler can not know whether a different compilation unit contains a subclass and a redefinition of the virtual function.  

    Note that in some previous versions, functions with complicated if-statements and return-statements could not be inlined. This limitation has been removed. Also, the default limitation on inline function size has been raised. With some programs, these changes will cause more functions to be inlined and can result in slower compilations and more code generation.

    To completely eliminate the inlining of C++ inline functions, use the +d option.

    Separately, the optimizer inlines functions at higher optimization levels (-xO4) based on the results of control flow and so forth. This inlining is automatic and is done irrespective of whether you declare a function "inline" or not.

Updated April 2011

Left Curve
Popular Downloads
Right Curve
Untitled Document
Left Curve
More Systems Downloads
Right Curve
Solaris 11.2 Banner RHS