Updated 2001/06/06

Forte Developer 6 update 2 FAQ: C++



Contents

  1. Boy, the Sun WorkShop[tm] and C++ compiler version numbers are confusing!
     
  2. How can I tell which versions are compatible?
     
  3. Can I mix compatibility mode (-compat) code with standard mode code?
     
  4. I have seen enormous compile times with compiler versions 5.0 and version 5.1 (compared to 4.2). Can I expect this problem to be fixed in the near future?
     
  5. We have noticed much larger binaries compared to the 4.2 version of the compiler. Is there a solution to this?
     
  6. How does the 5.3 compiler's runtime compare to earlier versions and with respect to gcc?
     
  7. Does C++ always inline functions marked with "inline" keyword? Or, why didn't I see functions inlined even though I wrote them that way?
     
  8. Why do I get a warning about a function not being expanded when I use +w -xO1 and not when I use +w +d?
     
  9. How do I get a C++ standard library (stdlib) that is fully compliant? Or, what functionality does the current libCstd not support?
     
  10. I need the C++ standard template library (STL). Where do I get it? Is there one for compatibility mode (-compat)?
     
  11. What standard library functionality is missing from libCstd?
     
  12. What are the consequences of the missing standard library functionality?
     
  13. stdlib streams are slower than gcc or KAI streams. This is a performance hit for me. Is there a solution in sight?
     
  14. Is there a version of tools7 library that works with standard streams? Or, will there be a tools8 available soon?
     
  15. What RogueWave libraries are "certified" for use with Forte Developer 6 update 1?
     
  16. How do I mix C++ or C programs with F77, F90, or F95 programs?
     
  17. How can I figure out which patches exist and what problems are solved in the current patches?
     
  18. Do I need to have patches to libC.so.5 and libCrun.so.1?
     
  19. Can I use the -ptr option to have multiple template repositories, or to share repositories among different projects? If not, what can I do?
     
  20. Can a single compilation process be distributed onto multiple processors? More generally, does a multiprocessor (MP) system always have better compile-time performance?
     
  21. I see an error message like this occassionally: SunWS_cache: Information: Database is locked, waiting... What does this mean? What causes it? Is any action expected of me? How do I get rid of it?
     
  22. Why does fprintf("%s",NULL) cause a segmentation fault?
     
  23. 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?
     
  24. 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?
     
  25. Why does the compiler say a member of an enclosing class is not accessible from a nested class?
     
  26. What causes the "pure virtual function call" message at run time?
     
  27. 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. Boy, the Sun WorkShop[tm] and C++ compiler version numbers are confusing!

    Here is a chart showing the correspondence between Sun WorkShop and C++ compiler versions:

    
        Sun WorkShop     C++ Compiler
        1.0                 4.0
        2.0                 4.1
        3.0                 4.2
        [4.0 version number not used]
        5.0                 5.0
        6 (not 6.0)         5.1
        6 update 1          5.2
        6 update 2          5.3
    

    Around the time Sun WorkShop 6 was released, Sun bought Forte[tm], and decided to use the Forte brand name for its WorkShop line. That decision came after the documents were printed, so during a transition period, some products are known by two names:

    
        Forte Developer 6         : same as Sun WorkShop 6
        Forte Developer 6 update 1: same as Sun WorkShop 6 update 1
        Forte Developer 6 update 2: same as Sun WorkShop 6 update 2
    





  2. How can I tell which 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 C++ 5.0, 5.1, 5.2, and 5.3 compilers in compatibility mode (-compat) are upward compatible with the 4.2 compiler. The actual object code from C++ 4.2 and versions 5.0, 5.1, 5.2, and 5.3 is fully compatible, but debugging information (stabs) emitted by later compilers is not compatible with earlier debuggers.

    The C++ 5.0, 5.1, 5.2, and 5.3 compilers in default standard mode are upward compatible. The actual object code is fully compatible, but debugging information (stabs) emitted by later compilers is not compatible with earlier debuggers.






  3. Can I mix compatibility mode (-compat) code with standard mode code?

    We recommend against, and do not support, mixing code in the same program, even through "plug-ins" or dynamically-loaded libraries for the following reasons:

    • The layout of class objects is different.

    • The calling sequence for functions is different.

    • The "name mangling" is different.

    • The exception-handling methods conflict.

    • The presence of two sets of iostream objects connected to the same file descriptors cause problems.

    Even when the two parts (compatibility mode and standard mode) of the program do not communicate, If an exception is thrown anywhere in the code, the program could crash immediately.

    You can link compatibility mode and standard mode object files together under some circumstances. The subject is covered in detail in the C++ Migration Guide that ships with the compiler. Refer to "Mixing Old and New Binaries" in Chapter 1. This guide is available online at http://docs.sun.com.






  4. I have seen enormous compile times with compiler versions 5.0 and version 5.1 (compared to 4.2). Can I expect this problem to be fixed in the near future?

    We have improved compile times considerably in 5.1patch01, version 5.2 and version 5.3.

    The table below shows the improvements in compile times for 17 test cases. Most of the test cases came from bug reports regarding the slowdown in compile time.

    Table 1: Compile Times By Version in Seconds
    Test gcc 4.2 5.0 5.1 5.2 5.3

    4221261

     

    11.0s

    40.1s

    34.7s

    18.9s

    14.6s

    4321922

     

    51.3s

    4,977s

    4,223.4s

    207.5s

    95s

    4294143

     

    6.0s

    14.0s

    21.0s

    14.1s

    12s

    4295782

    12.5s

     

    32s

    26.3s

    18.2s

    15.4s

    4307028(M3100)

    1,200s

    530.8s

    5,074s

    40,254.7s

    725s

    700s

    4313920

    900s

    27.1s

    2,265.8s

    15,064s

    176s

    50s

    4322356

     

    12.9s

    1,766.6s

    8,436.1s

    29s

    17.5s

    4327123

    32.0s

    46.4s

    496.4s

    17,018.4s

    55.0s

    42s

    4296476

    1s

    FAIL

    6.4s

    46.1s

    6.0s

    3.3s

    4303485

     

    FAIL

    1,992.7s

    886s

    24s

    20s

    4312121

     

    36.1s

    786.8s

    1,506.5s

    33s

    30s

    4343086

     

    3.0s

     

    13.9s

    13.5s

    10.1s

    Test 1

     

     

    10 hours plus

    7,980s

    1,582s

    944s

    Test 2

     

    117s

    259s

    742s

    77s

    60s

    system-c

     

     

     

    350s

    330s

    299s

    To cut compile times, try the following strategies with version 5.3 of the compiler. The more strategies you can implement, the better.

    1. In some extreme cases, inlining causes huge bloat. When either the -xO4 or -xO5 option is used, the code generator automatically inlines some functions. You may need to use a lower optimization level such as -xO3 You can use the -xinline option to prevent the automatic inlining of specific functions by the optimizer.

    2. Turn off the explicit inlining of larger functions. Refer to Question 7 for a discussion of explicit inlining.

    3. By default, all instances are put into the object's SunWS_cache subdirectory. If there is a huge amount of instantiation, then repository management can take up to 95% of compilation times. Check if you can use one of the template instantiation models that bypasses the template repository; explicit, global, static, and semiexplicit. Use the -instances=model option to specify the desired model. If your compile-time problem is instantiation, use of a different instantiation model can dramatically decrease compile times.

      Note that these alternative models impose programming style restrictions. For more information about template instantiation models, see "Compiling Templates" in the C++ User's Guide that ships with the compiler. This guide is available online at http://docs.sun.com.






  5. We have noticed much larger binaries compared to the 4.2 version of the compiler. Is there a solution to this?

    The binaries increase in size for -g compiles because, starting with version 5.0, the compiler generated lots of template debugging information . The 5.1 compiler greatly reduced the size of the generated debug information for many kinds of programs. The 5.2 and 5.3 compilers have added further improvements. In many cases, the binary decreases from 25% to over 50% in size. The improvements show up mostly for code using namespaces, templates, and class hierarchies with many levels of inheritance.

    Another reason for larger binaries is libCstd. In both version 5.0 and version 5.1, binaries are linked with libCstd.a; which is roughly a 4MB library. Because this is an archived library, quite a bit of it gets pulled into the binary.

    In version 5.2 we made libCstd available in shared library format (libCstd.so.1). This shared library can considerably reduce the size of binaries.

    We also provide libiostream.so.1 for compiles that use the -library=iostreams option to get the classic iostreams.

    There are other reasons for a larger binary, but these reasons are secondary to the increase in size caused by template debugging information or use of libCstd.a and libiostream.a. The other reasons are mostly likely to be corner cases.

    1. The compiler does more inlining now than with version 4.2. In some cases where the callee function is large, this increases the overall object file (.o) size. Refer to Question 7.

    2. In large and complex class hierarchies, the standard-mode method of generated virtual function calls can sometimes result in larger code than that produced by the 4.2 compiler or by compiling in compatibility mode. In these cases, you can reduce code size by compiling with -xO2 (or -O).  

    3. The -xO4 level optimization is more aggressive compared to earlier compilers. Similarly, the use of -xcrossfile may increase binary size due to more aggressive optimization. 

    4. With some programming styles, the default behavior generates a large number of initializers (one for each non-local static objects) in an object file (this is faster in terms of compile time). Turn this off with -features=no%split_init to collapse these into one function. This saves space, but possibly increases compile times in some extreme cases.

    In each of these cases, the generated code executes faster than it did previously.

    The following table compares binary sizes across compiler versions. The first number is the size of the object file (.o) in kilobytes. The second number, if available, is the size of the template cache in kilobytes.

    Table 2: Binary Size Comparisons in KB by Version
    Test 5.3 5.2 5.1 5.0 4.2

    4221261

    287

    263

    262

    272

    264

     

    36

    35

    41

    71

    49

    4294143

    920

    964

    1,073

    1,167

    1,132

     

    91

    91

    1,775

    2,653

    56

    4295782

    913

    916

    916

    1,665

     

     

    7

    5

    5

    5

     

    4307028(M3100)

    2,944

    2,784

    2,789

    3,189

    2,918

    4322356

    1,058

    1,758

    2,309

    1,534

    1,664

    4327123

    1,004

    1,036

    1,163

    1,513

    1,096

     

    21,680

    23,372

    578,023

    641,142

    15,543

    libCstd (-g)

    37,566

    35,934

    51,000

    119,000

     

    Stepanov (-g)

    98

    209

    217

    258

    227






  6. How does the 5.3 compiler's runtime compare to earlier versions and with respect to gcc?

    As with any benchmark, your results will vary. The following tables lists some of the commonly used benchmarks and shows how the compiler stacks up against those on a 450MHz UltraSPARC II system.

    The table lists two kinds of performance numbers for a set of standard benchmark tests.

    The entries ending with "s", such as 354.84s or 1.3s, represent time in seconds. The entries ending with "ms", such as 17ms or 168435ms, represent time in milliseconds. A smaller value means a faster program, so smaller is better.

    All other entries, except for the Stepanov entry, show the number of operations per unit time. A higher number means a faster program, so bigger is better.

    For Stepanov, the ratio measures the "abstraction penalty", and a smaller number is better.

    Table 3: C++ Runtime Comparisons in Seconds and Minutes
    Test 5.3 5.2 5.0 gcc2.95.2 kcc3.9a

    eon

    265s

    283s

    341s

    452s

    250s

     

    184s

    194s

    269s

    309s

    169s

     

    329s

    354.8s

    467s

    561s

    318s

    Haney

    1.56s

    2.19s

    3.01s

    2.57s

    NA

     

    3.78s

    4.27s

    4.22s

    5.69s

    NA

     

    2.68s

    2.92s

    2.68s

    3.24s

    NA

    oopack

    1.0s

    1.3s

    1.4s

    1.8s

    0.4s

     

    1.5s

    3.1s

    2.9s

    10.5s

    0.5s

     

    1.5s

    2.7s

    2.4s

    5.2s

    0.6s

     

    2.2s

    2.4s

    3.0s

    2.8s

    0.2s

    fft(ratio)

    151

    113.3

    103.4

    89.0

    111

    fib(ratio)

    260

    233.0

    108.2

    88.6

    260

    infilife(ratio)

    106

    92.4

    91.2

    89.8

    106

    life(ratio)

    133

    107.6

    109

    84.2

    133

    Stepanov

    6.8/1.23

    11.15/1.91

    18.73/3.46

    5.35/0.52

    9.60/4.06

    C++Bench

    2,199mins

    2,440mins

    2,423mins

    2,815mins

    3,253mins



    Table 4: Runtime Test Results for libCstd in Seconds and Microseconds
    Test 5.3 5.2 5.0 gcc2.95.2 kcc3.9a

    Espresso

    33s

    100s

    109s

    95s

    88s

    slowio

    19s

    39.4s

    37s

    11.5s

     

    map<1,000,000>

    1,575us

    2,387us

     

    2,192us

    2,581us

     

    2,078us

    2,737us

     

    3,619us

    3,551us

     

    831us

    858us

     

    1,257us

    1,815us

    list<50,000>

    14us

    17us

     

    16us

    60us

     

    129,504us

    168,435us

     

    195,252us

    169,058us

     

    5us

    6us

     

    7us

    44us

    strings

    1,159us

    2,523us

     

    575us

    1,912us






  7. Does C++ always inline functions marked with "inline" keyword? Or, 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. In compiler versions 5.1, 5.2, and 5.3, the inlining algorithm has been revamped to make it understand more constructs. However, there are still cases where it will not succeed. The restrictions are:

    • Starting in the 5.2 and 5.3 C++ compilers, 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.  

    • Functions with local static variables are not inlined. This limitation might be removed in future releases.

    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.






  8. Why do I get a warning about a function not being expanded when I use +w -xO1 and not when I use +w +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 will attempt 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 the +w option is used. 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.






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

    The current libCstd was developed for version 5.0 of the C++ compiler. That version did not support templates as members of classes. Some parts of the standard library require member templates, meaning that some functionality is missing. The missing functionality mostly shows up in container classes that have constructor templates allowing implicit type conversions. You have to write explicit conversions in your source code as a workaround.

    Beginning with WorkShop 6, the C++ compiler supports templates as members of classes, and can support a standard-conforming library. We cannot update the library without breaking source and binary compatibility, so we continue to ship a libCstd with the same limitations.

    You can find public implementations of standard libraries at gnu, SGI, and STLport web sites, and you can also purchase libraries from vendors such as RogueWave and Dinkumware. See also the following question about the STL.






  10. I need the C++ standard template library (STL). Where do I get it? Is there one for compatibility mode (-compat)?

    The C++ standard library that is distributed with the compiler contains the STL. You can use a different version of the standard library, but doing so is risky and good results are not guaranteed.

    To plug in a different STL, use the -library=no%Cstd option and point the compiler to your header files and library of choice. If the replacement library does not have its own iostreams library, and if you can use "classic" iostreams instead of standard iostreams, add -library=iostream to the command line. For detailed instructions, see "Replacing the C++ Standard Library" in the C++ User's Guide that ships with the compiler. This guide is available online at http://docs.sun.com.

    The most popular STL, STLport, works with some compiler versions and some Solaris versions. STLport 4.0 makes assumptions about standard C header files that are invalid on Solaris 8. Both compatibility mode and standard mode versions of this library are available. Details can be found at the following web site:

    http://stlport.org/
    





  11. 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 compatiblitiy. The following is a list of missing functionality for each disabled feature.

    • 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

    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*> {}






  12. 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>.






  13. stdlib streams are slower than gcc or KAI streams. This is a performance hit for me. Is there a solution in sight?

    Our default (ANSI) standard streams are not implemented very efficiently. The underlying RogueWave (RW) streams implementation (version 2.1.1) does too many lseeks and writes out data inefficiently. RogueWave has fixed this problem in a subsequent version of stdlib (version 2.2.3), but that version is not binary compatible with the 2.1.1 version; hence, its not offered by default.

    Here are some workarounds that you can try to alleviate the problem:

    • Use the -library=iostreams option. This uses "classic" iostreams instead of standard streams. These classes are known to be efficient. Unfortunately, using the classic iostreams means that you cannot use stdlib features and the whole program has to be compiled using -library=iostreams. Use of classic iostreams may also require some source code changes.
       

    • Use the STL from STLport.org, along with the -library=iostreams option. In both standard mode (the default) and compatibility mode (-compat) this seems to give a fairly reasonable performance (within 50% of gcc).
       

    • Use stdlib2.2.3 provided by RogueWave. Unfortunately, this library is not compatible with stdlib2.1.1, which is the default library provided with versions 5.0, 5.1, and 5.2 of the compiler, and therefore may not work if the application requires other middleware.






  14. Is there a version of tools7 library that works with standard streams? Or, will there be a tools8 available soon?

    Yes there is, but only with C++ 5.3. Use the -library=rwtools7_std command to link with this library.

    As of this writing, RogueWave has not released tools8.






  15. What RogueWave libraries are "certified" for use with Forte Developer 6 update 2?

    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.






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

    Starting with Workshop 6 update 1 (compiler version 5.2), 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.






  17. 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 Hot News Web page ( http://www.sun.com/forte/developer/hotnews.html) occasionally.

    Product patches can be downloaded from http://sunsolve.sun.com.






  18. Do I need to have patches to libC.so.5 and libCrun.so.1?

    Typically, the Solaris[tm] 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, so it is a good idea to pick up the latest patch available. The following table shows the current matrix of patch IDs as of July 2001.

    Please check for the latest package in the database. The package is called SUNWlibC (32bit) and SUNWlibCx(64bit).

    Table 5: libC and libCrun Patches
    Patch ID Solaris
    Operating System
    Architecture

    105591-10

    2.6  

    SPARC/v8

    104678-08

    2.6  

    Intel

    106327-09

    7

    SPARC/v8

    106300-10

    7

    SPARC/v9

    106328-09

    7

    Intel

    108434-02

    8

    SPARC/v8

    108435-02

    8

    SPARC/v9

    108436-02

    8

    Intel






  19. Can I use the -ptr option to have multiple template repositories, or to share repositories among different projects? If not, what can I do?

    The -ptr option is not supported in versions 5.0, 5.1, 5.2, or 5.3. Although it was available in version 4.2, it did not always work as users expected, and it caused many problems.

    The best advice is not to share repositories among different projects. The sharing of repositories is likely to cause problems more severe than the problem you are trying to solve. Compile only one project in any one directory. Use a different directory for the binaries associated with a different project.

    Beginning with version 5.0, the compiler puts a template repository in the same directory as the object file being generated. If you want to use multiple repositories for one project, generate an object file in the directory where you want the associated repository to be. At link time, all the repositories associated with the object files will automatically be searched for template instances. No compiler options are required.






  20. 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. If the simultaneous compilations require use of the template cache, contention for access to the cache can be a bottleneck. You should investigate options for avoiding the cache, such as the options described in 4c of this FAQ. For more information, see the "Compiling Templates" chapter in the C++ User's Guide that ships with the compiler. This guide is available online at http://docs.sun.com.






  21. I see an error message like this occassionally: SunWS_cache: Information: Database is locked, waiting... What does this mean? What causes it? Is any action expected of me? How do I get rid of it?

    When a program that uses templates is compiled, the compiler locks the output SunWS_cache directory whenever it needs to update the compilation state information in SunWS_cache/CC_state. If multiple processes that use templates try to compile in the same directory, only one process will acquire a lock at a time.

    The C++ compiler versions 4.2, 5.0, and 5.1 issue a message "SunWS_cache: Information: Database is locked, waiting..." whenever a process is waiting to acquire a lock. This message is just for informational purposes and should be ignored. The message means that some other compilation process has locked the database. When the other job is over, the current job will continue. You could get this message, say, by using dmake. You cannot get rid of this message. The latest C++ 5.2 patch and the C++ 5.3 compiler use a different locking scheme and do not issue this message.






  22. Why does printf("%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 will occur 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 /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.






  23. 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);
      }
      





  24. 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?

    The following test case compiles and links without errors with the C++ 5.0 compiler but causes link-time errors with later versions of the compiler:

    example% cat t.c
    
    #include <ostream>
    
    using std::ostream;
    
    template <class T> 
    class TList {
    public:
      friend ostream& operator<< (ostream&, const TList&);
    };
    
    template <class T>
    ostream& operator<< (ostream& os, const TList<T>& l)
    {
      return os; 
    }
    
    class OrderedEntityList {
    public:
      TList<int> *Items; 
      ostream& Print(ostream &) const;
    };
    
    ostream& 
    OrderedEntityList::Print(ostream& os) const
    {
      os << *Items;
      return os;
    }
    
    main()
    {
    }
    
    example% CC t.c
    
    Undefined			first referenced
    symbol  			    in file
    std::basic_ostream<char,std::char_traits<char> 
    >&operator<<(std::basic_ostream<char,std::char_traits<char> >&,const 
    TList<int>&) 4421826.o
    
    ld: fatal: Symbol referencing errors. No output written to a.out
    

    The test case is invalid according to the standard. The problem is that the declaration

    friend ostream& operator<< (ostream&, const TList&);
    

    does not refer to any template instance.

    The unqualified name lookup cannot match a template declaration even if one were visible at the point of the friend declaration. To get the friend declaration to match a template, you need either to declare it as a template function, or qualify the name.

    Either way, the declaration for the template must be visible at the point of the friend declaration.

    To summarize, the friend declaration does not refer to a template, but it declares a function that is the best match to the function call. (A non-template function is preferred over a template function if they are otherwise equal.)

    To following code is valid:

    template <class T> class TList; 
    // so we can declare the operator<< template
    
    template <class T> 
    ostream& 
    operator<< (ostream& os, const TList<T>& l) 
    { 
      return os; 
    } 
    
    template <class T> 
    class TList {
    public :
      // note the scope qualification on the function name
      friend ostream& ::operator<< (ostream&, const TList&);
    };
    





  25. Why does the compiler say a member of an enclosing class is not accessible from a nested class?
    class Outer {
        typedef int my_int;
        static int k;
        class Inner {
            my_int j;          // error, my_int not accessible
            int foo() {
                    return k; // error, k not accessible
    		}
    	};
    };
    

    According to the ARM and to the C++ Standard, a nested class has no special access to members of the enclosing class. Since my_int and k are private in Outer, only friends of Outer have access to them. In order to make a nested class a friend, you must first forward-declare the class, then make it a friend, as the following example shows:

    class Outer {
        typedef int my_int;
        static int k;
    															
    	// add these two lines ahead of the class definition 
        class Inner;  
        friend class Inner;
    																			
        class Inner {
            my_int j;         // OK
            int foo() {
                    return k; // OK
    		}
    	};
    };
    





  26. 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
      }
      





  27. 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. If you are compiling in default standard mode, 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
    };
    





Updated 2001/06/06

Copyright 2001 Sun Microsystems, Inc., 901 San Antonio Road, Palo Alto, CA 94303, U.S.A. All rights reserved. 

Sun, Sun Microsystems, the Sun logo, docs.sun.com, and Solaris are trademarks, registered trademarks, or service marks of Sun Microsystems, Inc. in the U.S. and other countries.