13.4.4 文字列out

String_varoutパラメータとして渡すと、参照先の前の値はすべて暗黙的に解放する必要があります。この要件を満たす上でC++マッピング実装に十分なフックを付与するために、文字列型にもCORBAネームスペースでString_out型が生成されます。この型は、文字列outパラメータ型としてのみ使用します。String_out型の全般的な形式は次のとおりです:

// C++
class String_out
{
  public:
    String_out(char*& p) : ptr_(p) { ptr_ = 0; }
    String_out(String_var& p) : ptr_(p.ptr_) {
       string_free(ptr_); ptr_ = 0;
    }
    String_out(String_out& s) : ptr_(s.ptr_) {}
    String_out& operator=(String_out& s) {
       ptr_ = s.ptr_; return *this;
   }
   String_out& operator=(char* p) {
      ptr_ = p; return *this;
   }
   String_out& operator=(const char* p) {
      ptr_ = string_dup(p); return *this;
   }
   operator char*&() { return ptr_; }
   char*& ptr() { return ptr_; }
private:
   char*& ptr_;

   // assignment from String_var disallowed
   void operator=(const String_var&);
};

最初のコンストラクタは、リファレンス・データ・メンバーをchar* &引数にバインドします。2番目のコンストラクタは、リファレンス・データ・メンバーをString_var引数が保持するchar*にバインドし、その文字列に対してstring_free()を呼び出します。3番目のコンストラクタはコピー・コンストラクタです。その引数のデータ・メンバーにバインドされる同じchar*に、リファレンス・データ・メンバーをバインドします。

ほかのString_outから代入すると、String_out引数によって参照されるchar*が、データ・メンバーによって参照されるchar*にコピーされます。char*のオーバーロードの代入演算子は、char*引数をデータ・メンバーに代入するだけです。constchar*のオーバーロードの代入演算子は、引数を複製して結果をデータ・メンバーに代入します。代入によって、保持されていた文字列が解放されることはありません。この点では、String_out型はchar*とまったく同じように動作します。char* &変換演算子は、データ・メンバーを返します。ptr()メンバー関数もデータ・メンバーを返しますが、暗黙的な変換の実行を避ける場合に使用できます。

String_varからString_outへの代入はできません。これは、メモリー管理にあいまいさが生じるためです。具体的には、String_varが所有する文字列をコピーせずにString_outに引き継ぐ必要があるのか、それともコピーする必要があるのかを判断できません。String_varからの代入が不可能なため、アプリケーション開発者は次のように明示的に指定しなければなりません。

// C++
void
A::op(String_out arg)
{
    String_var s = string_dup("some string");
    ...
    out = s;                // disallowed; either
    out = string_dup(s);    // 1: copy, or
    out = s._retn();        // 2: adopt
}

コメントで「1」とマークされた行では、呼出し側はString_varが保持する文字列を明示的にコピーし、結果をout引数に代入しています。また、呼出し側は、コメントで「2」とマークされた行で示すように、String_varに文字列の所有権を強制的に放棄させるというテクニックも使用できます。これにより、メモリー管理のエラーを発生させずにout引数に文字列を返すことができます。