                                                    更新日付: 2004 年 5 月 27 日

Sun[tm] Studio 9: C++ FAQ

    目次

        A.このリリースで追加された質問
        B.バージョン、パッチ、およびサポート
        C.コンパイラの互換性
        D.コーディングおよび診断
        E.ライブラリの互換性
        F.コンパイル時のパフォーマンスの向上
        G.実行時のパフォーマンスの向上

    ------------------------------------------------------------------

    A.このリリースで追加された質問

      1.それぞれのリリースで、どのような C++ コンパイラであるかを確認
        する信頼できる方法を教えてください。
  
      2.最近 Solaris OS にパッチをインストールしたのですが、コードが
        コンパイルされなくなりました。どうしてですか?
  
      3.foo.cc ファイルのコンパイル、または他のソースからの参照のいず
        れも行っていないにもかかわらず、foo.cc に関するエラーや警告が
        出力されます。原因を教えてください。
  
      4.-P オプションを使用して、前処理によって生成された foo.i ファイ
        ルをコンパイルすると、定義が重複していることを示すエラーメッ
        セージが返されます。原因を教えてください。
  
      5.C++ コンパイラのプリコンパイル済みヘッダーファイル機能を使い始
        めたのですが、コンパイル時のパフォーマンスが向上しません。どう
        してですか?
  
      6.小さなファイルに比べて、大きなファイルのコンパイルにかかる時間
        が長すぎます。どうしてですか?
  
      7.SPARC V9 アーカイブライブラリを動的ライブラリにリンクすると、
        エラーになります。どうしてですか?Sun Studio 8 では問題ありま
        せんでした。
  
      8.「SunWS_cache: Error: Lock attempt failed for SunWS_cache」と
        いうメッセージが返される原因を教えてください。
  
      9.標準ライブラリストリームが、gcc や KAI ストリームより低速です。
        パフォーマンスの低下が大きすぎます。解決策はあるのでしょうか ?
  
     10.リンカーから「ld: warning: symbol 'clog' has differing types」
        という警告が返されます。どうしてですか?
  
     11.-xarch=v8plus または -xarch=v8plusa を付けてコンパイルすると、
        STLport を使用するマルチスレッドプログラムがクラッシュします。
        どうしてでしょうか?
  
     12.abs() に対する呼び出しがあいまいであるという意味のメッセージが
        コンパイラから返されます。どうしてですか?
  
     13.一時オブジェクトはいつ破壊されるのでしょうか? 


    ------------------------------------------------------------------

      1.それぞれのリリースで、どのような C++ コンパイラであるかを確認
        する信頼できる方法を教えてください。 

        どのコンパイラにも、自身の情報を提供するいくつかのマクロが事前
        に定義されています。コンパイラのベンダーは、リリースが変わって
        も、そうした事前定義マクロが安定して動作するようにする努力をし
        ており、Sun の場合は、安定した公開インタフェースとして明記して
        います。
        
        お持ちのコンパイラを確認する方法として良いのは、事前定義マクロ
        の有無を確認して、用途に合った文字列を出力する小さなプログラム
        を作成することです。疑似プログラムを作成し、-E (または、他の
        コンパイラの場合は相当するオプション) を付けてそのプログラムを
        コンパイルすることもできます。
        
        C++ コンパイラの事前定義マクロについては、『C++ ユーザーズガイ
        ド』の索引の「マクロ」を参照してください。具体的には、
        __SUNPRO_CC の値は 3 桁の 16 進数です。最初の数字がメジャーリ
        リース、2 つ目の数字がマイナーリリース、3 つ目の数字がマイクロ
        リリースを表します。たとえば C++ 5.6 は 0x560 です。 
        
        以下に主な事前定義マクロの内容を示します。 
         
        #ifdef __sun
               Sun compiler
        #endif
        #ifdef __SUNPRO_C
               Sun C compiler /* __SUNPRO_C の値はバージョン番号 */
        #endif
        #ifdef __SUNPRO_CC
               Sun C compiler /* __SUNPRO_CC の値はバージョン番号 */
        #endif
        #ifdef __sparc
               generate code for SPARC architecture
        #endif
        #ifdef __sparcv9
               generate code for 64-bit SPARC architecture
        #endif
        #ifdef __i386
               generate code for Intel architecture
        #endif
        
      2.最近 Solaris OS にパッチを当てたのですが、コードがコンパイルさ
        れなくなりました。どうしてですか? 
        
        最近のバージョンの Solaris で提供している新しい数学関数が原因
        で、以前は正当であったコードが不当になった可能性があります。
        
        以前の <math.h> の関数はすべてdouble 型専用のバージョンでした。
        新しい Solaris ヘッダーおよびライブラリには、float および 
        long double 型の多重定義もあります。あいまいな呼び出しを回避す
        るため、整数型の引数を持つ関数の呼び出しで、明示的なキャストの
        追加が必要になることがあります。以下に例を示します。
        
        #include <math.h>
        extern int x;
        double      z1 = sin(x); // 現在はあいまい
        double      z2 = sin( (double)x ); // OK
        float       z3 = sin( (float)x ); // OK
        long double z4 = sin( (long double)x ); //  OK
        
        下記の Solaris パッチは、Solaris 8 および 9 用の libm パッチで
        実現されている ANSI C++ に準拠した <cmath> および <math.h> ラ
        イブラリサポートを提供します。 
        
        Solaris 9 SPARC (パッチ 111722-04) 
        Solaris 9 i386 (パッチ 111728-03) 
        Solaris 8 SPARC (パッチ 111721-04) 
        Solaris 8 i386 (パッチ 112757-01) 
        
      3.foo.cc ファイルのコンパイル、または他のソースからの参照のいず
        れも行っていないにもかかわらず、foo.cc に関するエラーや警告が
        出力されます。原因を教えてください。 
        
        ヘッダーファイルの foo.h にテンプレート宣言がある場合、デフォ
        ルトではコンパイラは、C++ のファイル拡張子を持つファイル foo 
        (foo.c、foo.cc、foo.C、foo.cpp、foo.c++) を探し、見つかった場
        合は、自動的にそのファイルを取り込みます。詳細は、『C++ ユー
        ザーズガイド』の「Template Definitions Searching」を参照してく
        ださい。
        
        ファイル foo.cc をこのように処理したくない場合、選択肢は 2 つ
        あります。
        
           o .h または .cc ファイルの名前を変更して、検索対象から排除
             されるようにする。 
           o -template=no%extdef オプションを指定することによって、
             テンプレート定義ファイルの自動検索を無効にする。しかしな
             がら、このオプションは、独立したテンプレート定義の検索も
             すべて無効にします。C++ 標準のライブラリ実装では、コンパ
             イラが独立した定義を検出するものと想定しています。このた
             め、すべてのテンプレート定義を明示的に取り込む必要があり、
             そうしないと定義独立モデルを使用できません。
        
             テンプレート定義モデルのさらに詳しい内容は、『C++ ユー
             ザーズガイド』の 5.2.1 および 5.2.2 節を参照してください。
             『C++ ユーザーズガイド』の索引に、定義独立モデルおよび定
             義取り込みモデルを説明している場所が記載されています。
        
      4.-P オプションを使用して、前処理によって生成された foo.i ファイ
        ルをコンパイルすると、定義が重複していることを示すエラーメッ
        セージが返されます。原因を教えてください。 
        
        デフォルトでは、コンパイラは、テンプレート定義とその宣言が分離
        していることを黙認します。テンプレート定義モデルのさらに詳しい
        内容は、『C++ ユーザーズガイド』の 5.2.1 および 5.2.2 節を参照
        してください。『C++ ユーザーズガイド』の索引に、定義独立モデル
        および定義取り込みモデルを説明している場所が記載されています。
        
        必要なテンプレートの定義がない宣言が .h または .i ファイルにあ
        ると、コンパイラはテンプレート定義ファイルを探します。.h また
        は .i ファイルと名前が同じで、拡張子が c か cc、C、c++、cpp い
        ずれかのファイルをテンプレート定義ファイルとみなします。C++ マ
        ニュアルで説明しているように、そうしたファイルが存在すると、自
        動的に取り込まれます。
        
        foo.cc ファイルが -P を付けてコンパイルされて、foo.i が生成さ
        れ、必要なテンプレートの宣言はあるが、定義がないと仮定します。
        コンパイラは定義ファイルを探し、foo.cc を検出します。foo.cc 
        ファイルが自動的に取り込まれ、定義が重複することになります。
        
        コンパイラのテンプレート定義の検索は、-template=no%extdef オプ
        ションを指定することによって無効にできます。しかしながら、この
        オプションは、独立したテンプレート定義の検索もすべて無効にしま
        す。C++ 標準のライブラリ実装では、コンパイラが独立した定義を検
        出するものと想定しています。
        
        この場合は、.i ファイルをコンパイルしたいわけですから、単に
        ファイル名を変更して、一意の名前にします。独立したテンプレート
        のコンパイルを無効にする必要はありません。以下に例を示します。
        
                CC -P foo.cc
                mv foo.i foo_prep.i
                CC -c foo_prep.i
        
        -E オプションを使用して、前処理済みファイルを生成する場合、こ
        の方法は機能しないことに注意してください。-E オプションは取り
        込まれたファイルの名前の記録をとるため、引き続き .cc ファイル
        が自動的に検出される可能性があります。
        
      5.C++ コンパイラのプリコンパイル済みヘッダーファイル機能を使い始
        めたのですが、コンパイル時のパフォーマンスが向上しません。どう
        してですか? 
        
        プリコンパイル済みヘッダーを使うことによって、コンパイル時間が
        短縮される保証はありません。プリコンパイル済みヘッダーを使用す
        ると、ファイルを直接コンパイルしたときにはないオーバーヘッドが
        多少生じます。パフォーマンスの向上のためには、プリコンパイルで
        取り除ける多少の冗長性がプリコンパイル済みヘッダーに存在する必
        要があります。
        
        たとえば、プリコンパイルすることでメリットが得られる可能性が高
        いプログラムとしては、多数のシステムヘッダーや入出力ストリーム、
        STL ヘッダー、プロジェクトヘッダーを含んでいるプログラムがあり
        ます。こうしたファイルには、条件付きコンパイルコードが含まれて
        いるためです。一部のヘッダーは複数回取り込まれるため、ファイル
        全体の if 全体をスキャンしさえすれば、冗長なインクルードで行わ
        れることは何もないことがわかります。一般に、システムヘッダーに
        は数百個のマクロがあります。
        
        プリコンパイル済みヘッダーを使用するということは、数十のファイ
        ルを開く代わりに 1 つのファイルを開くことを意味します。コメン
        トや余分な空白と同じようにして、何もしない複数のインクルードが
        取り除かれます。ヘッダー内のマクロは事前に展開されます。一般に、
        こうしたことが、コンパイル時間の大幅な短縮につながります。
        
      6.小さなファイルに比べて、大きなファイルのコンパイルにかかる時間
        が長すぎます。どうしてですか? 
        
        おそらく問題はファイルのサイズではありません。考えられる原因は
        3 つあります。
        
           o ファイル内の関数のサイズと最適化レベル
             
             最適化度の高い大きな関数は処理に時間がかかり、大量のメモ
             リーを必要とすることがあります。コードで広範囲に大きなマ
             クロが使用されている場合、小さく見える関数が、マクロ展開
             後に非常に大きくなることがあります。
             
             最適化なし (-xO? や -O? オプションを付けない) でコンパイ
             ルしてみてください。コンパイルが短時間に終了した場合、お
             そらく問題は、非常に大きな関数がファイルに 1 つ以上存在し
             ていて、最適化にかなりの時間とメモリーを要することにあり
             ます。
             
             また、コンパイルに使用したコンピュータに、コンパイルを実
             行するのに十分な物理メモリーがあることを確認してください。
             十分なメモリーがないと、最適化フェーズで時間がかかること
             があります。
             
           o インライン関数
             
             C および C++ のインライン関数はマクロに似ていて、コンパイ
             ル時間に影響を与えます。関数呼び出しをインラインに展開す
             ると、大量のコードに変換されることがあります。コンパイラ
             は、2 つ以上の小さな関数ではなく 1 つ大きな関数に対処する
             ことになります。
             
             関数のインライン化を無効にすると、コンパイル時間が短縮さ
             れることがしばしばあります。当然のこととして、たいていの
             場合、こうして生成されるコードの実行速度は低下します。
             
             詳細は、『C++ ユーザーズガイド』の -xinline および「Using
             Inline Functions」の説明を参照してください 
             
           o C++ のクラステンプレート
             
             C++ テンプレートが指定されている場合、コンパイラは呼び出
             されたテンプレートに基づいてコードを生成します。1 行の
             ソースコードに対して、1 つ以上のテンプレート関数の生成が
             必要になることがあります。つまり、テンプレートそのものが
             コンパイル速度を大幅に低下させているのではなく、元のソー
             スコードの見た目よりもコンパイラが処理しなければならない
             コードが多いということです。
             
             たとえば、以下のような関数をすでに含む標準ライブラリがな
             かったと仮定すると。ソースコードのこの行からは、241 個の
             関数が生成されることになります。
             
             cout << "value = " << x << endl;
        
      7.SPARC V9 アーカイブライブラリを動的ライブラリにリンクすると、
        エラーになります。どうしてですか?Sun Studio 8 では問題ありませ
        んでした。 
        
        V9 用の新しいデフォルトのコンパイラアドレスコードモデルは、
        -xcode=abs44 です。これは、前の -xcode=abs64 に比べてパフォー
        マンスを向上させます。しかしながら、この新しいコードモデルは、
        動的ライブラリ内では使用できません。この問題に対する解決策は 2
        つあります。
        
           o -xcode=pic13 または -xcode=32 を付けてオブジェクトファイ
             ルを再コンパイルする。この方法を推奨します。ほぼいつでも、
             適切な解決策です。
        
           o -xcode=abs64 を付けてオブジェクトファイルを再コンパイルす
             る。この方法では、動的ライブラリが共有できなくなります。
             別のメモリー領域にコピーするときに、プロセスごとにライブ
             ラリを書き換える必要があります。この方法は、パフォーマン
             ス上の制約が大きく、システム共有率が低い条件下で非常に長
             時間実行するアプリケーションに対して有用です。
        
      8.「SunWS_cache: Error: Lock attempt failed for SunWS_cache」と
        いうメッセージが返される原因を教えてください。 
        
        テンプレートキャッシュに関して「lock attempt failed」というエ
        ラーメッセージが返される主な原因は 2 つあります。
        
           o キャッシュに対して保持していたロックが解除されない形で
             コンパイルが異常終了するか、強制終了させられるた。この情
             報は、古いバージョンのコンパイラで発生することがあります。
             新しいバージョンおよび最新のパッチが当てられた古いコンパ
             イラでは、コンパイラの終了方法に関係なく必ずロックが解除
             されるようになっています。単にロックファイルを削除しても
             かまいませんが、たいていキャッシュが壊れているため、そう
             すると、さらに問題が起きます。最も安全な方法は、テンプ
             レートキャッシュ全体を削除することです。
        
           o コンパイラプロセスがテンプレートキャッシュに書き込みを行
             えない。詳細は、umask(1) のマニュアルページを参照してくだ
             さい。具体的には、内部にキャッシュまたはファイルを作成す
             るプロセスの umask で、同じキャッシュにアクセスする必要が
             ある他のプロセスによるキャッシュへの書き込みを許可してお
             く必要があります。ディレクトリが NFS ファイルシステムにマ
             ウントされている場合は、システムを読み取り/書き込みマウン
             トする必要があります。 
        
      9.標準ライブラリストリームが、gcc や KAI ストリームより低速です。
        パフォーマンスの低下が大きすぎます。解決策はあるのでしょうか ?
        
        この問題を解決するには、リンク時に新しい C++ コンパイラオプ
        ションの -sync_stdio=no を指定するか、sync_with_stdio(false) 
        関数への呼び出しを追加して、再コンパイルします。
        
        stdlib 2.1.1 のパフォーマンス上の最大の問題は、デフォルトで C 
        stdio と C++ ストリームの同期をとることです。cout へのあらゆる
        出力が、その都度ただちにフラッシュされます。プログラムが 
        stdout ではなく cout に大量の出力を行うと、この過度のバッファ
        フラッシュによって、プログラムの実行時のパフォーマンスが大きな
        影響を受けることがあります。C++ 規格では、この動作が必要とされ
        ていますが、必ずしもすべての実装がこの仕様を満たしているわけで
        はありません。次のプログラムは、同期をとらないと問題が発生する
        場合の具体例です。このプログラムは末尾に改行の付いた「Hello 
        beautiful world」という一行を出力するものです。 
        
            #include <iostream>
            #include <stdio.h>
            int main()
            {
                std::cout << "Hello ";
                printf("beautiful ");
                std::cout << "world";
                printf("\n");
            }
        
        しかし、cout および stdout が独立してバッファリングされている
        場合、このプログラムは期待された出力を行わない可能性があります。
        
        実行可能ファイルを再コンパイルできない場合は、リンク時に新しい
        C++ コンパイラオプションの -sync_stdio=no を指定してください。
        このオプションは、プログラム出力が発生する前のプログラム初期化
        時に sync_with_stdio( ) を呼び出します。
        
        再コンパイル可能な場合は、プログラム出力の前に 
        sync_with_stdio(false) に対する呼び出しを追加することによって、
        出力の同期をとる必要がないことを指示します。以下は、呼び出し例
        です。
        
                #include <iostream>
                int main(int argc, char** argv)
                {
                        std::ios::sync_with_stdio(false);
                }
        
        sync_with_stdio に対する呼び出しは、プログラムの最初の呼び出し
        にします。
        
        -sync_stdio の詳細は、『C++ ユーザーズガイド』または C++ マ
        ニュアルページの CC(1) を参照してください。
        
     10.リンカーから「ld: warning: symbol 'clog' has differing types」
        という警告が返されます。どうしてですか? 
        
        同じプログラム内で libm.so.2 と旧式の入出力ストリームライブラ
        リがリンクされると、リンカーは、異なる種類の弱いシンボルのペア
        があることを警告します。この警告は無視してかまいません。
        
        Solaris 10 では、デフォルトの数学ライブラリは libm.so.2 で、
        C99 規格で求められているように、このライブラリの大域の名前空間
        には、「clog」という複素数対数関数が含まれています。これに対し、
        -compat=4 または -library=iostream を指定することによって C++ 
        の旧式の入出力ストリームを使用すると、大域の名前空間にバッファ
        付き標準出力ストリームの「clog」が使用されます。(標準入出力ス
        トリームには、この矛盾するシンボルはありません。) 
        
        ヘッダーおよびライブラリが調整されて、これらの「clog」シンボル
        はそれぞれ暗黙に名前が変更されるため、1 つのプログラムでその両
        方を使用できます。しかし、元のシンボルを探す古いバイナリが引き
        続きリンクできるようにするには、これらライブラリのそれぞれで元
        のシンボルのスペルを弱いシンボルとして保持する必要があります。
        
        このため、入出力ストリームと数学ライブラリの宣言が使用されるよ
        うにするには、これらのエンティティを自分で宣言するのではなく、
        適切なシステムヘッダーをインクルードします。
        
     11.-xarch=v8plus または -xarch=v8plusa を付けてコンパイルすると、
        STLport を使用するマルチスレッドプログラムがクラッシュします。
        どうしてでしょうか? 
        
        元々、STLport には、-xarch=v8plus または -xarch=v8plusa を付け
        てコンパイルしたとき、正しいマルチスレッド動作を妨げるバグがあ
        りました。このバグは修正されていますが、この修正には STLport 
        ヘッダーの変更と、いくつかの STLport オブジェクトの変更が含ま
        れています。以前のバージョンの STLport ヘッダーを使ってコンパ
        イルしたコードは、新しいプログラムにリンクする前に C++ 5.6 か
        パッチを当てた以前のリリースで再コンパイルする必要があります。
        
     12.abs() に対する呼び出しがあいまいであるという意味のメッセージが
        コンパイラから返されます。どうしてですか? 
        
        C++ 規格の節 26.5 では、abs 関数を次のように多重定義することを
        求めています。
        
           o <stdlib.h> および <cstdlib> 

             int  abs(int);
             long abs(long);
             
           o <math.h> および <cmath> 

             float       abs(float);
             double      abs(double);
             long double abs(long double);
        
        かなり最近まで、Solaris 上で使用できる abs は従来の int 版だけ
        でした。どのような数値型で abs を呼び出しても、値は、
        <stdlib.h> または <cstdlib> がインクルードされているものとして、
        暗黙でint 型に変換され、int 版の abs が呼び出されました。 
        
        最近の更新によって、Solaris ヘッダーおよびライブラリは C++ の
        数学関数に関する 規格に準拠したものになっています。
        
        たとえば、<stdlib.h> ではなく、<math.h> をインクルードして、整
        数型の引数で abs を呼び出した場合、コンパイラは、3 つある浮動
        小数点型バージョンの abs 関数のうちの 1 つを選択する必要があり
        ます。整数値は任意の浮動小数点型に変更でき、他に優先する変換は
        ありません(参考: C++ 規格 13.3.3 節)。このため、この関数呼び出
        しはあいまいになります。つまり、あいまいエラーは、C++ 規格に準
        拠しているコンパイラであれば、どれでも返されます。
        
        整数型の引数で abs 関数を呼び出す場合、その適切な宣言を使用さ
        れるようにするには、標準ヘッダーの <stdlib.h> または <cstdlib>
        をインクルードします。浮動小数点型の値で abs を呼び出す場合は、
        <math.h> または <cmath> もインクルードします。
        
        簡単なプログラミングの習慣として、<math.h> か <cmath> をインク
        ルードする場合は、<stdlib.h> または <cstdlib> もインクルードす
        ることを推奨します。
        
        同様のことは、cos や sqrt などの他の数学関数にも当てはまります。
        現在の Solaris のヘッダーおおびライブラリは C++ 規格に準拠して
        おり、それら関数の float、double、および long double の多重定
        義バージョンを提供しています。たとえば整数型の値で sqrt を呼び
        出した場合、かっては 1 つのバージョンの sqrt しかなかったため、
        コンパイルが行われていました。しかし、現在は 3 つの浮動小数点
        バージョンがあるため、整数値を目的の浮動小数点型にキャストする
        必要があります。 
        
                double root_2 = sqrt(2); // エラー
                double root_2 = sqrt(2.0); // OK
                double x = sqrt(int_value); // エラー
                double x = sqrt(double(int_value)); // OK
        
     13.一時オブジェクトはいつ破壊されるのでしょうか? 
        
        コンパイラが一時オブジェクトを作成する理由としては、便宜上のこ
        ともあれば、言語規則でそのことが求めてられているためのこともあ
        ります。たとえば関数が返す値は一時オブジェクトで、型変換の結果
        も一時オブジェクトです。
        
        オリジナルの C++ の規則では、一時オブジェクト ("temp") は、そ
        れが作成されたブロックが終わるまでの間にいつでも破壊することが
        できました。そうした C++ コンパイラは、ブロックの終わり (閉じ
        る右中括弧) で temp を破壊しました。
        
        数年にわたる激しい討議の後、C++ 委員会は、temp を破壊すべき位
        置について結論に達しました。それは、temp が作成された式全体が
        終わる位置です。通常、この位置は、その式が現れる文が終わる位置
        です。これが、C++ 規格の規則です。
        
        しかしながら、Sun の C++ を使用している多くのプログラムが、お
        そらく無意識のうちに、ブロックの終わりまで temp が残っているこ
        とに依存していると予想されるため、コンパイラのデフォルトの動作
        は変更されていません。すなわち、デフォルトでは、一時オブジェク
        トは作成されたブロックの終わりの位置で破壊されます。
        
        規格に準拠した動作 (temp が作成された式が完全に終わる位置でそ
        の temp を破壊する) が必要な場合は、コンパイル時オプションの 
        -features=tmplife を使用してください。
        
        プログラム全体を通じてこのオプションを使用する必要はありません。
        モジュールで作成された一時オブジェクトは、コンパイル時にこのオ
        プションが有効かどうかに従って、そのモジュール内の式が終わる位
        置またはブロックが終わる位置で破壊されます。


    ------------------------------------------------------------------

    B. バージョン、パッチ、およびサポート

      1.「標準」および「旧式」入出力ストリームの違いはなんですか ? 
        また、この問題に関する参考文献を教えてください。 

      2.どの C++ コンパイラに互換性があるのか、見分ける方法を教えてく
        ださい。 

      3.Sun Studio 9 で使用できるライブラリとして「認定」される 
        RogueWave ライブラリを教えてください。 

      4.どのようなパッチがあって、現在のパッチでどのような問題が解決さ
        れるのかを調べるには、どうすればよいでしょうか ? 

      5.libC.so.5 および libCrun.so.1 に対するパッチは必要でしょうか ?


    ------------------------------------------------------------------

      1.標準入出力ストリームと旧式入出力ストリームの違いはなんですか ?
        また、この問題に関する参考文献を教えてください。 

        2 つのライブラリの設定と実装がまったく異なります。 単純な入出
        力のプログラミングインタフェースは酷似しています。 しかし、
        ユーザー独自のストリームクラスやマニピュレータの書き込みなど、
        複雑な動作については大きく異なります。

        本バージョンの「旧式」入出力ストリームライブラリは、 C++ 3.x 
        および 4.x に付属するバージョンと互換性があります。このリリー
        スに付属するマニュアルのほかにも、次のような参考文献があります。

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

        標準入出力ストリームライブラリについては、C++ Standard で説明
        されています。 その他にも、次のような参考文献があります。 

          o Nicolai Josuttis 
            The C++ Standard Library 
            Addison-Wesley 1999 
            (C++ 標準ライブラリ全般に関するチュートリアル) 

          o Angelika Langer および Klaus Kreft 
            Standard C++ IOStreams and Locales 
            Addison-Wesley 1999 
            (入出力ストリームとロケールに関するチュートリアル) 

        単純な入出力を実装するためのソースコードは、どちらの入出力スト
        リームも似通っています。 簡単に移行するために、規格外のヘッ
        ダー <iostream.h>、<fstream.h>、および <strstream.h> が標準の
        入出力ストリームに装備されています。 これらのヘッダーは、旧式
        の入出力ストリームにあるグローバルネームスペースと酷似した宣言
        セットを提供します。これらのヘッダーを使用すると、デフォルトで
        標準入出力ストリームが使用されます。旧式の入出力ストリームが使
        用されるようにするには、-library=iostream を付けてコンパイルお
        よびリンクを行います。

        たとえば、次のコードは、Sun のコンパイラを使用して旧式と標準の
        両方の入出力ストリームで機能します。ただし、一部のコンパイラは
        使用されません。 

        #include <iostream.h>

        class myclass {
        public:
                myclass(int i) : k(i) { }
                friend ostream& operator<<(ostream&,; const myclass&);
        private:
                int k;
        };

        // ユーザー独自の出力演算子
        ostream& operator<<(ostream& os, const myclass& m)
        {
            os << m.k;
            return os;
        }

        int main()
        {
            // cout、 cin を使用した単純な入出力
            cout << "Enter a number: " << endl;
            int val;
            if( ! (cin >> val) ) {
                cout << "Invalid entry, using zero" << endl;
                val = 0;
            }

            // ユーザー独自の出力演算子を使用
            myclass m(val);
            cout << "Value is " << m endl;
        }

        次のいずれかの方法で Sun コンパイラを使用して、このコードを
        コンパイル、実行します。

        example% CC example.cc  # 標準モードで標準入出力ストリームを使用
        example% CC -library=iostream example.cc  # 標準モードで旧式の入出力ストリームを使用
        example% CC -compat=4 example.cc  # C++ 4.2 互換モード


      2.C++ コンパイラのバージョン間の互換性はどのようになっています
        か ? 

        まず、定義しておきます。 「上方互換」とは、先行バージョンの
        コンパイラでコンパイルされたオブジェクトコードが後続バージョン
        のコンパイラでコンパイルされたコードとリンクできることを意味し
        ます。この場合、最終リンクで最新のコンパイラを使用する必要があ
        ります。

        C++ 4.0、4.1、および 4.2 コンパイラは上方互換性があります。 
        (C++ 4.2 マニュアルに記述されているように、コンパイラのバー
        ジョン間にいくつかの「名前の符号化」問題があります)。

        C++ のバージョン 5.0 - 5.6 までのコンパイラは、互換モード 
        (-compat) で、4.2 コンパイラと上方互換です。C++ 4.2 とバー
        ジョン 5.0 - 5.6 で生成された実際のオブジェクトコードとは完全
        に互換性がありますが、後続コンパイラが発するデバッグ情報 (スタ
        ブ) は先行デバッガと互換性がありません。

        デフォルト標準モードでは、C++ の 5.0 - 5.6 までのコンパイラは
        上方互換性があります。 実際のオブジェクトコードは完全に互換性
        がありますが、後続コンパイラの発するデバッグ情報 (スタブ) は先
        行デバッガと互換性がありません。

      3.Sun Studio 9 で使用できるライブラリとして「認定」される 
        RogueWave ライブラリを教えてください。 

        Sun のコンパイラの各バージョン用に、どのベンダーがどの製品を保
        証しているのかを確実に追跡することはできません。 そして、この
        FAQ を常に最新に維持するのも、依然として難しい状態です。 C++ 
        コンパイラの特定バージョンについてベンダーが製品テストを行なっ
        たかどうかについては、そのベンダーに問い合わせる必要があります

        ただし、Sun のコンパイラに付属している一部の RogueWave ライブ
        ラリについては、出荷バージョンと互換性があることを暗黙に保証し
        ます。

      4.どのようなパッチがあって、現在のパッチでどのような問題が解決さ
        れるのかを調べるには、どうすればよいでしょうか ? 

        製品パッチの最新情報については、開発者向けの次のポータルサイト
        をご確認ください。
        http://developers.sun.com/prodtech/cc

        製品のパッチは http://sunsolve.sun.com からダウンロードできま
        す。

      5.libC.so.5 および libCrun.so.1 に対するパッチは必要でしょうか ?

        コンパイラは、そのリリース日付において最新の SUNWlibC パッチと
        ともに出荷されます。

        一般に、Solaris[tm] オペレーティングシステムには、これらのライ
        ブラリの最新版が付属しています。 しかし、しばしば、これらのラ
        イブラリには、バグの修正やパフォーマンスの改良のためのパッチが
        提供されます。 そうしたパッチは常に累積されていて、常に後方互
        換であるため、提供されている中でも最新のパッチを利用することを
        推奨します。 次の表は、2002 年 3 月現在の最新のパッチ ID を示
        しています。

        データベースに最新のパッケージがあるか確認してください。 パッ
        ケージの名前は SUNWlibC (32 ビット) または SUNWlibCx (64 ビッ
        ト) です

                    表 1 libC および libCrun のパッチ

            パッチ ID              Solaris             アーキテクチャ
                            オペレーティングシステム

            108434-17                 8                SPARC/v8

            108435-17                 8                SPARC/v9

            108436-15                 8                x86

            111711-11                 9                SPARC/v8

            111712-11                 9                SPARC/v9

            111713-08                 9                x86


    C. コンパイラの互換性

      1.互換モード (-compat) のコードと標準モードのコードを混在させる
        ことはできますか ? 

      2.C++ または C プログラムと F77、F90、または F95 プログラムを組
        み合わせるには、どうすればよいでしょうか ? 

    ------------------------------------------------------------------

      1.互換モード (-compat) と標準モードのコードを混在させることはで
        きますか ? 

        Sun では混在を推奨しません。「プラグイン」や動的読み込みライブ
        ラリであっても、次の理由から、同じプログラム内のコードの混在は
        サポートしていません。

          o クラスオブジェクトの配置が異なる。

          o 関数の呼び出し処理が異なる。

          o 「名前の符号化」処理が異なる。

          o 例外処理方法が矛盾する。

          o 2 つの入出力ストリームオブジェクトを同じファイル記述子に接
            続すると問題が発生する。

        プログラムの 2 つの部分 (互換モードと標準モード) が通信しない
        ときでも、コード内で例外が送出(スロー)されると、プログラムがす
        ぐにクラッシュする可能性があります。

        状況によっては、互換モードと標準モードのオブジェクトファイルを
        まとめてリンクできます。 この問題については、コンパイラに付属
        している『C++ 移行ガイド』で詳しく説明されています。 第 1 章
        「新旧バイナリの混在」を参照してください。このガイドは、 
        http://docs.sun.com からオンラインで入手できます。

      2.C++ または C プログラムと F77、F90、または F95 プログラムを組
        み合わせるには、どうすればよいでしょうか ? 

        Workshop 6 update 1 (コンパイラのバージョンは 5.2) 以降、
        -xlang={f90|f95|f77} オプションを使用できるようになりました。
        このオプションは、リンク行に必要なライブラリとそれらのライブラ
        リの必要な出現順を正確に割り出すようドライバに指示します。

        この -xlang オプションは、C コンパイラには使用できません。 C 
        ルーチンと Fortran ルーチンを組み合わせるには、cc でコンパイル
        し、Fortran リンカーでリンクする必要があります。


    D. コーディングおよび診断
      1.コンパイラから標準の例外クラスについてのあいまいさが報告される
        のはなぜですか ? 

      2.C++ 5.3 で派生仮想関数のスロー指定に関してエラーが出されるのは
        なぜですか ? 

      3.プログラムをリンクするとテンプレートインスタンスが失われるのは
        なぜですか ? インスタンスはテンプレートキャッシュ内にあるよう
        です。 

      4.+w2 を使用しているとき、または +w2 +d を使用していないときに、
        関数は展開されないという警告メッセージが表示されるのはなぜです
        か ? 

      5.-ptr オプションを使って、複数のテンプレートリポジトリを使用し
        たり、複数のプロジェクト間でリポジトリを共有したりできますか ?
        できない場合は、どのようにすればよいでしょうか ? 

      6.次のようなメッセージが表示されることがあります。 SunWS_cache:
        情報: 「データベースがロックされています。待機中です...」これ
        はどういう意味ですか? 原因は何ですか? I何か処置が必要ですか?
        どうすればこのメッセージを出さないようにできますか ? 

      7.printf("%s",NULL) がなぜセグメント例外の原因になるのですか ? 

      8.sqrt() の呼び出し方法によって、複素数の平方根の虚部の符号が異
        なります。 これはなぜですか ? 

      9.クラステンプレート中のフレンド関数はインスタンス化されず、リン
        ク時にエラーになります。 C++ 5.0 ではこのようなことはありま
        せんでした。今回のバージョンでエラーになるのはなぜですか ? 

     10.入れ子になったクラスから包含するクラスのメンバーにアクセスで
        きない、というのはなぜですか ? 

     11.実行時に「pure virtual function call (純粋関数呼び出し)」メッ
        セージが表示される原因は何ですか ? 

     12.派生クラスの仮想関数は、識別形式の異なる基底クラスの仮想関数を
        隠す、というのはなぜですか ? 他のコンパイラの場合、このコード
        には何も問題がありません。 

    ------------------------------------------------------------------

      1.コンパイラから標準の例外クラスについてのあいまいさが報告される
        のはなぜですか ? 

        Solaris では、標準ヘッダーの <math.h> に、標準の Unix に必要な
        構造体「exception」用の宣言があります。 using 宣言または
        using 指令を使用して C++ 標準例外クラスを大域スコープに入れる
        と、衝突が発生します。 

        // Example 1

        #include <math.h>
        #include <exception>
        using namespace std; // using 宣言
        exception E;  // エラー、例外があいまい

        // Example 2:

        #include <math.h>
        #include <exception>
        using std::exception; // using 宣言
        exception E;  // エラー、例外に対する多重宣言
        
        using 宣言 と using 指令を比較すると、名前解決は微妙に異なりま
        す。そのため、エラーメッセージは完全に一致しません。

        回避策:
            1.<math.h> の代わりに <cmath> を使用してください。 Solaris
              の <cmath> には、C および C++ 規格で指定されている宣言し
              か含まれません。 <math.h> の UNIX 固有の機能が必要である
              場合、この解決策は使用できません。 

            2.<math.h> も使用する場合は、using std::exception;と記述し
              ないでください。 明示的に std::exception を記述するか、
              typedef を使用して標準例外クラスにアクセスしてください。
              次に例を示します。 

            #include <math.h>
            #include <exception>
            std::exception E; // OK
            typedef std::exception stdException; // OK
            stdException F; // OK

            3.using namespace std; を記述しないでください。 
            C++ ネームスペース std には非常に多くの名前が含まれるため
            実際のコードでこの指令を使用すると、アプリケーションコード
            またはサードパーティのライブラリと衝突する可能性があります
            (C++ プログラミングに関する書籍や記事では、この using 指令
            を持たせて小さなサンプルプログラムをさらに単純化しているこ
            とがあります)。 個々の using 宣言か、明示的な修飾名を使用
            します。 

      2.C++ 5.3 で派生仮想関数のスロー指定に関してエラーが出されるのは
        なぜですか ? 

        5.3 C++ コンパイラが新たに強制する C++ 規則では、派生クラスの
        仮想関数は、上書きされる関数が許容する例外のみを許容できます。
        上書き関数の制限を強化することはできますが、制限を緩めることは
        できません。 次の例で考えてみてください。 

        class Base {
        public:
            // int 型の例外はスローできるが、それ以外はスローできない
            virtual void f() throw(int);
        };
        class Der1 : public Base {
        public:
            virtual void f() throw(int); // ok, 同じ指定
        };
        class Der2 : public Base {
        public:
            virtual void f() throw(); // ok, より厳しい制限
        };
        class Der3 : public Base {
        public:
            virtual void f() throw(int, long); // エラー, long は認められない
        };
        class Der4 : public Base {
        public:
            virtual void f() throw(char*); // エラー, char* は認められない
        };
        class Der5 : public Base {
        public:
            virtual void f(); // エラー, 例外を認めている
        };

        次のコードは、C++ 規則の施行理由を示しています。 

        #include "base.h" // Base クラスを宣言
        void foo(Base* bp) throw()
        {
            try {
               bp->f();
            }
            catch(int) {
            }
        }

        Base::f() が int 例外のみをスローするように宣言されているため
        関数 foo は、int 例外の捕捉が可能であり、例外のエスケープを許
        容しないことを宣言します。 誰かが後にクラス Der5 を宣言した場
        合を考えてみましょう。ここでの宣言で、上書き関数は任意の例外を
        スローし、Der5 ポインタを foo に渡すことができます。 関数 foo 
        のコンパイル時に可視コードに問題がない場合でも、関数 foo は無
        効になります。

      3.プログラムをリンクするとテンプレートインスタンスが失われるのは
        なぜですか ? インスタンスはテンプレートキャッシュ内にあるよう
        です。 

        テンプレートキャッシュは、コンパイラが生成するオブジェクトファ
        イル間の依存関係リストを保有し、テンプレートインスタンスは
        キャッシュに含まれています。 ただし、現在のコンパイラは、
        -instances=extern が指定されている場合にのみテンプレートキャッ
        シュを使用するようになっていることに注意してください。オブジェ
        クトファイルを移動または名前変更するか、オブジェクトファイルを
        ライブラリに結合した場合、キャッシュへの接続が失われます。 
        2 つの代替手段を次に示します

          1.オブジェクトファイルを直接的に最終ディレクトリに生成します
            テンプレートキャッシュも同じディレクトリに配置されます。

            次の例は使用しないでください。 

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

            代わりに次の例を使用してください。 

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

            makefile マクロでプロセスをカプセル化できます。

          2.CC -xar を使用すると、中間的なアーカイブファイル (.a) を作
            成できます。 それぞれのアーカイブには、アーカイブ内のオブ
            ジェクトが使用するすべてのテンプレートインスタンスが含まれ
            ます。 これらのアーカイブを最終プログラムにリンクします。 
            一部のテンプレートインスタンスは異なるアーカイブで重複しま
            すが、同一アーカイブで重複しないようにリンカーが処理します

            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

      4.+w2 を使用しているとき、または +w2 +d を使用していないときに、
        関数は展開されないという警告メッセージが表示されるのはなぜです
        か ? 

        C++ コンパイラには、次の 2 種類のインライン化があります。 パー
        サーによって行われる C++ の inline 関数のインライン化と、コー
        ドジェネレータによって行われる最適化のインライン化です。 C お
        よび Fortran コンパイラには、最適化のインライン化だけしかあり
        ません (1 つのプラットフォームでは、すべてのコンパイラに対して
        同じコードジェネレータが使用されます)。

        C++ コンパイラのパーサーは、暗黙にあるいは明示的に inline とし
        て宣言されたすべての関数のインライン化を展開しようと試みます。
         関数が大きすぎると、パーサーは、+w2 オプションを使用している
         場合にだけ警告を発します。 +d オプションは、パーサーが関数を
         インライン化しないようにします。 そのため、+d を使用すると警
         告メッセージが表示されません。 (また、-g オプションを指定して
         も、C++ インライン関数はインライン化されません)。 -xO オプ
         ションは、このタイプのインライン化には何も影響を与えません。

        最適化のインライン化は、プログラム言語に左右されません。 -xO4
        またはそれより高い最適化レベルを選択すると、コードジェネレータ
        は、関数がソースコード内でどのように宣言されていようとも、すべ
        ての関数を検査して、置き換える利点があれば、関数呼び出しをイン
        ラインコードで置き換えます。 最適化のインライン化 (あるいは、
        関数のインライン化の失敗) に関するメッセージは何も表示されませ
        ん。 +d オプションは、最適化のインライン化には何も影響を与えま
        せん。

      5.-ptr オプションを使って、複数のテンプレートリポジトリを使用し
        たり、複数のプロジェクト間でリポジトリを共有したりできますか ?
        できない場合は、どのようにすればよいでしょうか ? 

        -ptr オプションは、バージョン 5.0 - 5.6 ではサポートされていま
        せん。バージョン 4.2 で提供されていましたが、必ずしもユーザー
        の期待どおりに機能せず、多くの問題を発生させていました。

        最良のアドバイスは、複数のプロジェクト間でリポジトリを共有しな
        いことです。 リポジトリを共有すると、解決を図れないほど深刻な
        問題が発生する可能性があります。 1 つのプロジェクトは 1 つのデ
        ィレクトリだけでコンパイルしてください。 別のプロジェクトのバ
        イナリには別のディレクトリを使用してください。

        バージョン 5.0 以降、コンパイラは、生成するオブジェクトファイ
        ルと同じディレクトリにテンプレートリポジトリを格納します。 1 
        つのプロジェクトに複数のリポジトリを使用する場合は、関係するリ
        ポジトリを格納するディレクトリにオブジェクトファイルを作成して
        ください。 リンク時、それらオブジェクトファイルに関係するリポ
        ジトリに対して、自動的にテンプレートインスタンスの検索が行われ
        ます。 コンパイラオプションは必要ありません。

      6.次のようなメッセージが表示されることがあります。 SunWS_cache:
        「情報: データベースがロックされています。待機中です...」 これ
        はどういう意味ですか ? 原因はなんですか? 何か処置が必要ですか?
        どうすればこのメッセージを出さないようにできますか ? 

        テンプレートを使用するプログラムをコンパイルするときに、
        SunWS_cache/CC_state 内のコンパイル状態情報の更新が必要な場合
        コンパイラは、必ず SunWS_cache 出力ディレクトリをロックします
        テンプレートを使用する複数のプロセスが同じディレクトリでコンパ
        イルしようとする場合には、一度に 1 つのプロセスだけがロックを
        取得します。

        バージョン 4.2、5.0、および 5.1 の C++ コンパイラは、ロック取
        得待ちのプロセスがあるときは必ず、 「SunWS_cache: 情報: データ
        ベースがロックされています。待機中です...」 というメッセージを
        出力します。 このメッセージは単に情報を通知するためのものです
        から、無視してください。 このメッセージは、ある別のコンパイル
        プロセスがデータベースをロックしたということを意味しています。
        その別のジョブが終了すると、現在のジョブが続行されます。 dmake
        を使用しているために、このメッセージが出ると考えられます。 こ
        のメッセージを出さないようにすることはできません。 最新の C++ 
        5.2 パッチ、C++ 5.3 コンパイラ、5.4 コンパイラ、および 5.5 コ
        ンパイラでは、別のロック方式が採用されており、このメッセージは
        出ません。

    7.printf("%s",NULL) がなぜセグメント例外の原因になるのですか ? 

        アプリケーションの中には、NULL 文字ポインタは空文字列へのポイ
        ンタと同じ扱いをしなければならないと誤って認識しているものがあ
        ります。 これらのアプリケーションでは、NULL 文字ポインタがアク
        セスされるとセグメント違反が発生します。

        いくつかの理由により、 *printf() の関数ファミリには NULL ポイ
        ンタのチェック機能がありません。 これだけに限りませんが、次の
        ようなことが挙げられます。

            1.チェック機能を待たせると、誤った安心感を与える。 プログ
              ラマに、printf() への NULL ポインタ引き渡しがうまくいっ
              たと思い込ませてしまいます。

            2.プログラマが移植性のないコードを書くことを助長する。 
              ANSI C、XPG3、XPG4、SVID2、および SVID3 では、
              printf("%s", pointer) には NULL で終わる文字の配列への 
              pointer ポイントがなければならないと規定されています。

            3.デバッグが難しくなる。 プログラマが NULL ポインタを
              printf() に渡してからプログラムがコアに入るのであれば、
              デバッガを使用すれば、不正なポインタを指定した printf()
              呼び出しを簡単に見つけ出すことができます。 しかし、 
              printf() が "(NULL ポインタ)" と出力することにより、
              そのバグを非表示にした場合、その後で進行するほかのプログ
              ラムは、ある実際のデータが欲しいときに、
              "(NULL ポインタ)" を解釈しようとするでしょう。 その時点
              では、実際の問題がどこに隠れているか判断することは不可能
              かもしれません。 

        NULL ポインタを *printf に渡すアプリケーションがある場合は、ロ
        ケーション 0 に値 0 を設定するためのメカニズムを提供する特定の
        共有オブジェクト /usr/lib/0@0.so.1 を使用することができます。
        このライブラリは、NULL ポインタの型による違いに関連するすべて
        のエラーをマスクするので、このライブラリは、コードを修正するま
        での一時的な回避策としての使用に限定してください。

      8.sqrt() の呼び出し方法によって、複素数の平方根の虚部の符号が異
        なります。これはなぜですか ? これはなぜですか ?

        この関数の実装は、「C99 csqrt Annex G 仕様」で規定されています
        たとえば、次のコード例の出力を見てください。

        complex sqrt (3.87267e-17, 0.632456) 
        float sqrt (3.87267e-17, -0.632456)
        
        1.互換モードで libcomplex を使用した例: 
        
        #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;
        }

        2.標準モードで libCstd を使用した例: 

        #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;
        }

        3.complex の sqrt 関数は、atan2 を使用して実装されます。次の例
        は atan2 を使用することによって起こる問題を示したものです。
        このプログラムの出力は以下のとおりです。 

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

        1 つめの例では、atan2 の出力は負の数になり、2 つめの例では正の
        数です。 これは、最初の引数として -0.0 または 0.0 のどちらが渡
        されるかによります。 
          
        #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);
        }

      9.クラステンプレート中のフレンド関数はインスタンス化されず、リン
        ク時にエラーになります。 C++ 5.0 ではこのようなことはありませ
        んでした。今回のバージョンでエラーになるのはなぜですか ?

        次のテストケースは、C++ 5.0 コンパイラでは、エラーなしにコンパ
        イルおよびリンクが行われますが、以降のバージョンのコンパイラで
        は、リンクタイムエラーが発生します。 

        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 test
        
        規格によると、このテストケースは無効です。 問題点は以下の宣言
        にあります
 
        friend ostream& operator (ostream&, const TList&);
        
        上の宣言は、いずれのテンプレートインスタンスも参照していません
        
        非修飾名の参照は、フレンド宣言の 1 箇所で認識可能であるとして
        も、テンプレート宣言と一致しません。 フレンド宣言をテンプレー
        トと一致させるには、フレンド宣言をテンプレート関数として宣言す
        るか、または名前を修飾する必要があります。 
        
        どちらの方法でも、テンプレート用の宣言は、フレンド宣言の 1 箇
        所で認識可能である必要があります。 
        
        つまり、フレンド宣言はテンプレートを参照しませんが、関数呼び出
        しにもっとも一致する関数を宣言します。 (ほかの点で等しいのであ
        れば、テンプレート関数よりもテンプレートでない関数の方がのぞま
        しいと言えます)。 
        
        次のコードは有効です。 

        template <class T> class TList; 
        // これで、operator<< テンプレートを宣言できる

        template <class T> 
        ostream& 
        operator (ostream& os, const TList<T>& l) 
        { 
          return os; 
        } 

        template <class T> 
        class TList {
        public :
          // 関数名のスコープ修飾に注意
          friend ostream& ::operator (ostream&, const TList&);
        };

     10.入れ子になったクラスから包含するクラスのメンバーにアクセスで
        きない、というのはなぜですか ? 
         
        class Outer {
            typedef int my_int;
            static int k;
            class Inner {
                my_int j;     // エラー、my_int にはアクセスできない
                int foo() {
                        return k; // エラー、k にはアクセスできない
                        }
                };
        };
         
        ARM および C++ 標準によると、入れ子になったクラスは、包含する
        クラスのメンバーに特別にアクセスすることはありません。 my_int 
        および k は Outer 内で非公開なので、Outer のフレンドだけがメン
        バーにアクセスできます。 入れ子になったクラスをフレンドにする
        ためには、クラスを前もって宣言してからフレンドにする必要があり
        ます。以下に例を示します。 
        
        class Outer {
            typedef int my_int;
            static int k;
                // 次の 2 行をクラス定義の前に追加
            class Inner;  
            friend class Inner;

            class Inner {
                my_int j;         // OK
                int foo() {
                        return k; // OK
                        }
                };
        };

     11.実行時に「pure virtual function call (純粋仮想関数呼び出し)」
        メッセージが表示される原因は何ですか ?

        プログラム内に、あるエラーが発生すると必ず、「pure virtual 
        function call (純粋関数呼び出し)」メッセージが表示されます。 
        このエラーは、次の 2 つのどちらかの場合に起こります。 
        
          1.このエラーは、抽象クラスのコンストラクタまたはデストラクタ
            から、外部関数に「this」パラメータを渡したことによって発生
            します。 構築および破壊時に、「this」は、コンストラクタま
            たはデストラクタ自身のクラスの型を持ち、最終的に構築される
            クラスの型は持ちません。 そこで純粋仮想関数の呼び出しを終
            えることができます。 次の例で考えてみてください。 
          
            class Abstract;

            void f(Abstract*);

            class Abstract {
            public:
                    virtual void m() = 0; // 純粋仮想関数
                    Abstract() { f(this); }   // コンストラクタが "this" を渡す
            };

            void f(Abstract* p)
            {
                    p->m();
            }

            「Abstract」コンストラクタから f が呼び出されると、
            「this」は「Abstract*」型となり、関数 f は純粋仮想関数 m 
            を呼び出そうとします。 

          2.明示的な修飾子指定を行わずに定義した純粋仮想関数を呼び出そ
            うとした場合にも、このエラーが起こることがあります。 本体
            に純粋仮想関数を指定することはできますが、呼び出し時には修
            呼び出すことができます。 

            class Abstract {
            public:
                    virtual void m() = 0; // 本体は後で提供される
                    void g();
            };

            void Abstract::m() { ... } // m の定義

            void Abstract::g()
            {
                    m(); // エラー、純粋仮想の m を呼び出そうとしている
                    Abstract::m(); // OK、呼び出しは完全に修飾されている
            }

     12.派生クラスの仮想関数は、識別形式の異なる基底クラスの仮想関数を
        隠す、というのはなぜですか ? 他のコンパイラの場合、このコード
        には何も問題がありません。 

        C++ の規則では、多重定義はスコープ内でのみ認められ、スコープを
        超えるものは認められません。 基底クラスは、派生クラスのスコー
        プを取り巻くスコープ内にあると考えられます。 そのため、派生ク
        ラス内で宣言された名前は、基底クラス内のあらゆる関数を隠し、多
        重定義できません。 この基本的な C++ 規則は、ARM よりも旧式で
        す。 

        ほかのコンパイラが、何も異常を表示しないとしても、これにより損
        害を被ります。なぜなら、コードは、期待するとおりには動作しない
        からです。 Sun のコンパイラは、そのコードを受け付けるときに警
        告を表示します。 (正当なコードですが、おそらく期待どおりには動
        作しません。) 

        多重定義されたセットに基底クラス関数を含めたい場合は、基底クラ
        ス関数を現在のスコープに入れるために手を加える必要があります。
        デフォルトの標準モードでコンパイルを行っている場合は、宣言の使
        用を追加できます。 

        class Base {
        public:
                virtual int    foo(int);
                virtual double foo(double);
        };

        class Derived : public Base {
        public:
                using Base::foo; // 基底クラス関数を多重定義セットに追加
                virtual double foo(double); // 基底クラスバージョンを置き換える


    E. ライブラリの互換性

      1.完全準拠の C++ 標準ライブラリ (stdlib) の入手方法を教えてくだ
        さい。 あるいは、現在の libCstd がサポートしていない機能には、
        どのようなものがありますか ? 

      2.C++ 標準のテンプレートライブラリ (STL) が必要です。 どこで入手
        できるのでしょうか ? 互換モード (-compat) 用のものはあるのでし
        ょうか ? 

      3.libCstd で失われた標準ライブラリ機能にはどのようなものがありま
        すか ? 

      4.標準ライブラリの機能が失われることで、どのような影響があるので
        しょうか ? 

      5.標準ストリームで機能する tools7 ライブラリバージョンはあります
        か ? あるいは tools8 はまもなく入手できるようになるのでしょう
        か ? 

    ------------------------------------------------------------------

      1.完全準拠の C++ 標準ライブラリ (stdlib) の入手方法を教えてくだ
        さい。 あるいは、現在の libCstd がサポートしていない機能には、
        どのようなものがありますか ? 

        このリリースには、STLport の Standard Library 実装のバージョン
        4.5.3 がオプションの標準ライブラリとして含まれています。
        STLport は C++ 規格に厳密に準拠していながら、一般的な拡張機能
        も保持しています。 ただし、デフォルトで使用される標準ライブラ
        リとのバイナリ互換性はありません。

        現在の libCstd は、バージョン 5.0 の C++ コンパイラ用に開発さ
        れました。 このバージョンは、クラスのメンバーとしてテンプレー
        トをサポートしていません。 標準ライブラリの一部には、メンバー
        テンプレートが必要であり、このことは一部機能が失われることを意
        味します。 これは特に、暗黙の型変換を可能にするコンストラクタ
        テンプレートを持つコンテナクラスにおいて起こります。 その場合
        は、回避策としてソースコード内に明示的な型変換を記述する必要が
        あります。

        バージョン 5.1 以降、C++ コンパイラはクラスのメンバーとして
        テンプレートをサポートしていて、規格に準拠したライブラリを使用
        できます。 ソースとバイナリレベルの互換性を損なうことなくライ
        ブラリを更新することはできないため、サンでは、同じ制限がある 
        libCstd を引き続き出荷しています。

        gnu と SGI の Web サイトでは、パブリック版の標準ライブラリが配
        布されています。また、RogueWave、Dinkumware などのベンダーから
        ライブラリを購入することもできます。 STL については、次の質問
        を参照してください。

      2.C++ 標準のテンプレートライブラリ (STL) が必要です。 どこで入手
        できるのでしょうか。 互換モード (-compat) 用のものはあるので
        しょうか ? 

        C++ コンパイラは現在、STLport の Standard Library 実装バー
        ジョン 4.5.3 をサポートしています。デフォルトのライブラリは現
        在も libCstd ですが、STLport 製品を代わりに使用できるようにな
        りました。 このリリースには、静的アーカイブ libstlport.a と動
        的ライブラリ libstlport.so の両方を含んでいます。 

        次のコンパイラオプションを指定すると、libCstd を無効にして 
        STLport を使用できます。

        -library=stlport4

        デフォルトの C++ 標準ライブラリ libCstd と STLport の両方が 
        STL を含んでいます。 別のバージョンの標準ライブラリを使用でき
        ますが、危険が伴い、良好な結果を保証できません。

        別の STL をプラグインするには、 -library=no%Cstd オプションを
        使用して、コンパイラが実際に使用するヘッダーファイルおよびライ
        ブラリを見つけられるようにします。 交換用のライブラリに専用の
         iostreams がなく、標準の iostreams の代わりに「従来」の
         iostreams を使用できる場合は、コマンド行に -library=iostream
        を追加します。 詳細な手順については、コンパイラに付属する『C++
        ユーザーズガイド』の「C++ 標準ライブラリの置き換え」を参照して
        ください。 このガイドは、http://docs.sun.com からオンラインで
        入手できます。

        このリリースでは、-compat モードに対応した標準ライブラリ機能は
        提供していません。 サードパーティのライブラリ (LTLport など) 
        を -compat モード用に構成できる場合もありますが、このリリース
        はそのような構成をサポートしません。
        
      3.libCstd で失われた標準ライブラリ機能にはどのようなものがありま
        すか ? 

        標準ライブラリは、元は (C++ 5.0 では) コンパイラ中にメンバーテ
        ンプレートおよび部分の特殊化を必要とする機能をサポートせずに構
        築されたものです。 これらの機能は C++ 5.1 以降、使用可能ですが
        標準ライブラリ内で有効にすることはできません。これらは下方互換
        性を維持するためです。下記は、各機能で無効にされ、その機能性が
        失われた機能リストです。

        o 無効にされた機能: メンバーテンプレート関数

          + <complex> 内の 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>&)

          + <utility> 内の pair クラス:

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

          + <locale> 内の locale クラス:

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

          + <memory> 内の auto_Ptr クラス:

            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>();

          + <list> 内の list クラス: 

            メンバーテンプレートのソート

          + ほとんどのテンプレートクラス: 

            テンプレートコンストラクタ

        o 無効にされた機能: メンバーテンプレートクラス

          <memory> 内の auto_ptr クラス:
          template <class Y> class auto_ptr_ref{}; 
          auto_ptr(auto_ptr(ref<X>&);

        o 無効にされた機能: 部分的に特殊化されている関数テンプレートの
          引数の多重定義

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

          + map、multimap、 set、multiset、basic_string、vector、
            reverse_iterator、および istream_iterator クラスの場合:

            bool operator!= ()

          + map、multimap、 set、multiset、basic_string、vector、およ
            び reverse_iterator クラスの場合:

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

          + map、multimap、 set、multiset、basic_string、および vector
          クラスの場合:

            void swap()
         
        o 無効にされた機能: デフォルトのパラメータを使ったテンプレート
          クラスの部分特殊化

        <algorithm> では、次のテンプレート関数 (非メンバー) はサポート
        されません。

        count(), count_if()

        <iterator> では、次のテンプレートはサポートされません。

        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);


      4.標準ライブラリの機能が失われることで、どのような影響があるので
        しょうか ? 

        C++ 規格では正当なコードがコンパイルされないことがあります。

        もっともよくあるのは、ペアの第 1 要素は const であるのに、その
        ようには宣言されていないマップを作成している場合です。 メン
        バーコンストラクタテンプレートは、必要に応じ暗黙で pair<T, U> 
        を pair<const T, U> に変換します。 しかし、コンストラクタがな
        いために、変換されずに、コンパイルエラーになります。

        マップ内のペアの第 1 要素を変更することはできないため、もっと
        も簡単な解決策は、ペア型を作成するときに明示的な const を使用
        することです。 たとえば、pair<int, T> ではなく 
        pair<const int, T> を使用します。また、map<int, T> ではなく 
        map<const int, T> を使用します。

      5.標準ストリームで機能する tools7 ライブラリバージョンはあります
        か ? あるいは tools8 はまもなく入手できるようになるのでしょう
        か ? 

        はい、あります。ただし、C++ 5.3、5.4、5.5 および 5.6 のみです。
        -library=rwtools7_std コマンドを使用してこのライブラリとリンク
        してください。

        RogueWave は Tools.h++ の機能を変更しており、現在では 
        SourcePro 製品の一部としてのみ提供しています。 そのような理由
        から、Tools.h++ version 8 は存在しません。


    F. コンパイル時のパフォーマンスの向上

      1.バージョン 4.2 と比べて、バージョン 5.0 および 5.1 のコンパイ
        ラのコンパイル時間は大幅に長くなっています。 将来、この問題は
        解決されるのでしょうか ? 

      2.バージョン 4.2 のコンパイラと比べてバイナリのサイズがかなり大
        きくなります。 この問題の解決策はあるのでしょうか ? 

      3.1 つのコンパイルプロセスを複数のプロセッサに分散できるでしょう
        か ? 一般的に、マルチプロセッサ (MP) システムの方がコンパイル
        時のパフォーマンスは常に良いのでしょうか ? 

    ------------------------------------------------------------------

      1.バージョン 4.2 と比べて、バージョン 5.0 および 5.1 のコンパイ
        ラのコンパイル時間は大幅に長くなっています。 将来、この問題は
        解決されるのでしょうか ? 

        5.1 のパッチ 01、バージョン 5.2、5.3、5.4、5.5、5.6 で、大幅に
        コンパイル時間を改善しました。コンパイラのパフォーマンスに満足
        できない場合、次の推奨事項に留意してください。

            a.極端な場合、インライン化は膨大な時間がかかる原因になりま
            す。 -xO4 または -xO5 のいずれかのオプションを使用すると、
            コードジェネレータがいくつかの関数を自動的にインライン化し
            ます。 -xO3 のような低い最適化レベルを使用する必要があるか
            もしれません。オプティマイザが特定関数を自動的にインライン
            化しないようにするには、-xinline オプションを使用できます

            b.大きな関数の明示的なインライン化を無効にします。 明示的
            なインライン化の詳細については、以下を参照してください。

      2.バージョン 4.2 のコンパイラと比べてバイナリのサイズがかなり大
        きくなります。 この問題の解決策はあるのでしょうか ? 

        -g オプションでコンパイルを行うと、バージョン 5.0 からコンパイ
        ラがテンプレートのデバッグ用の大量の情報を書き出すため、バイナ
        リのサイズが大きくなります。 バージョン 5.1 では、多くの種類の
        プログラムについて、そうしたデバッグ情報のサイズは大幅に縮小さ
        れます。 5.2、5.3、5.4、5.5、5.6 コンパイラでは、さらに改良さ
        れ、多くの場合に、バイナリサイズの縮小率は 25% から 50% 強に
        なっています。 こうした改良は、コードで名前空間やテンプレート、
        多数の継承レベルを持つクラス階層が使用されている場合に特に顕著
        です。

     3. 1 つのコンパイルプロセスを複数のプロセッサに分散できるでしょう
        か ? 一般的に、常にマルチプロセッサ (MP) システムの方がコンパ
        イル時のパフォーマンスは常に良いのでしょうか ? 

        コンパイラそのものはマルチスレッド化されていません。 しかし、
        コンパイラは 1 回のコンパイルで常に多数の他のプロセスを同時に
        動作させるため、MP システムの方がパフォーマンスの向上を期待で
        きます。

        dmake (コンパイラに付属しているツールの 1 つ) を使用すると、
        複数のコンパイルを同時に実行できます。 


    G. 実行時のパフォーマンスの向上

      1.C++ は、"inline" キーワードの付いた関数を常にインライン化する
        のでしょうか ? あるいは、そのように記述したとしても、インライ
        ン化されない関数があるのは、どうしてでしょうか ? 

      2.stdlib ストリームは、gcc または KAI ストリームより低速です。 
        パフォーマンスの低下が大きすぎます。 解決策はあるのでしょうか?

    ------------------------------------------------------------------

      1.C++ は、"inline" キーワードの付いた関数を常にインライン化する
        のでしょうか ? あるいは、そのように記述したとしても、インライ
        ン化されない関数があるのはどうしてでしょうか ? 

        基本的に、コンパイラは、inline 宣言を指令とみなし、そのように
        宣言された関数をインライン化しようとします。バージョン 5.1 か
        ら 5.6 までのコンパイラでは、インライン化アルゴリズムが改良さ
        れ、より多くの構文を理解するようになっています。 しかし 、それ
        でも、構文を理解できないケースが存在します。そうしたケースを次
        に示します。

        バージョン 5.2 - 5.6 の C++ コンパイラでは、ほとんど実行される
        ことのない一部関数呼び出しは展開されません。この変更は、コンパ
        イル速度、出力コードサイズ、および実行時速度の均衡をとる上で役
        立ちます。

        たとえば、静的な変数初期化で使用される式は 1 度だけ実行される
        ため、式中の関数呼び出しは展開されません。 インライン関数 
        func は、静的変数の初期化式中で呼び出されると、展開されないこ
        とがあることに注意してください。ほかの場所でインライン化された
        ままです。 同様に、例外ハンドラ中の関数呼び出しは、これらの
        コードにめったに実行されないので、展開されない可能性があります

        再帰関数は、最初の呼び出しレベルに対してのみインライン化されま
        す。 コンパイラは、再帰関数の呼び出しをあいまいにインライン化
        できません。 現在の実装は、インライン化されている任意の関数へ
        の初回呼び出しの時点で停止します。

        時として、小さな関数に対する呼び出しでさえもインライン化されな
        いことがあります。 この理由は、展開後の合計サイズが大きすぎる
        ということです。 たとえば、func1 が func2 を呼び出し、func2 が
        func3 を呼び出す、というような場合があります。 これらの関数が
        小さくて、再帰的な呼び出しはない場合でも、コンパイラがそれらす
        べてを展開した場合には、展開後のサイズの合計が大きすぎる可能性
        があります。

        多くの標準テンプレート関数は、小さいけれども深い呼び出し
        チェーンを持っています。 このような場合、2、3 個の呼び出しレベ
        ルだけが展開されます。 

        コンパイラは、goto 文、ループ、および try/catch 文を含む C++ 
        インライン関数をインライン化しません。 しかし、-xO4 レベルでは
        オプティマイザによってインライン化することがあります。

        大きな関数はインライン化されません。 C++ コンパイラのコンパイ
        ラとオプティマイザはともに、インライン化後の関数のサイズに制限
        があります。 この制限はサンとしての一般的な推奨事項です。 特別
        にこのサイズを緩める、または厳しくしたい場合は、内部オプション
        について技術サポートに問い合わせてください。

        仮想関数がサブクラス内で再定義されていないとしても、インライン
        化することはできません。 これは、別のコンパイルユニットにサブ
        クラスと仮想関数の再定義が含まれているのかどうかをコンパイラが
        認識できないためです。

        以前の一部のバージョンでは、複雑な if 文と return 文を持つ関数
        がインライン化できませんでした。 しかし、この制限はなくなりま
        した。 また、インライン関数に対するデフォルトのサイズ制限も緩
        和されています。 プログラムによっては、こうした修正によってイ
        ンライン化可能な関数が増えますが、コンパイル時間が長くなり、
        コードのサイズが大きくなることがあります。

        C++ インライン関数のインライン化を完全に無効にするには、+d オ
        プションを使用します。

        これとは別に、最適化レベルが高い (-xO4) 場合、オプティマイザは
        、制御フローなどの結果に基づいて関数をインライン化します。 こ
        のインライン化は自動的で、関数が "inline" 宣言されているかどう
        かに関係なく行われます。

      2.stdlib ストリームは、gcc または KAI ストリームよりも低速です。
        パフォーマンスの低下が大きすぎます。 解決策はあるのでしょうか?
         
        C++ 5.4 では、デフォルトのストリームライブラリのパフォーマンス
        が向上しています。問題がある場合には、次の解決策を参考にしてく
        ださい。 

        -library=iostreams オプションの利用。 このオプションは、標準ス
        トリームではなく「従来」の iostreams を使用します。 これらのク
        ラスは効率的であることがわかっています。 残念なことに、従来の 
        iostreams を使用するということは、 stdlib の機能が利用できなく
        なり、-library=iostreams を使って、プログラム全体をコンパイル
        する必要があることを意味します。 また、従来の iostreams を使用
        するには、一部ソースコードの変更が必要になることがあります。 

        -library=stlport4 および -library=iostreams オプションの指定に
        よる STLport の利用。 標準モード (デフォルト) と互換モード 
        (-compat) の両方で、かなりのパフォーマンスが得られるようです
         (gcc の 50% 以内)。 

                                          更新日付: 2004 年 5 月 27 日
    ------------------------------------------------------------------

    Copyright (C) 2004 Sun Microsystems, Inc., All rights reserved. 
    Use is subject to license terms.

