オープン配列
目次
オープン配列のサポート
Object Pascal には、サイズの指定されていない配列を関数に渡すことができる "オープン配列" という構文要素があります。C++ では、この型を直接にはサポートしていませんが、次の 2 つのパラメータを明示的に渡すことで、オープン配列パラメータを持つ Object Pascal 関数を呼び出すことができます。
- 配列の先頭要素を指すポインタ
- 配列の最後のインデックス値であるカウント(配列のサイズつまり配列要素の数から 1 を差し引いたもの)
-
- メモ: これまで、カウント パラメータには
_Size
サフィックスが付いていましたが、現在は代わりに_High
サフィックスが付いています。このパラメータ値は_Size パラメータ値 - 1
と同等です。
- メモ: これまで、カウント パラメータには
たとえば、math.hpp の Mean 関数は、Object Pascal と C++ では次のように宣言されています。
Delphi での宣言:
function Mean(Data: array of Double): Double;
C++ での宣言:
double __fastcall Mean(double *Data, const int Data_High);
次のコードは、C++ で Mean 関数を呼び出す場合の例です。
double d[] = { 3.1, 4.4, 5.6 };
// explicitly specifying last index
double x = Mean(d, 2) ;
// better: use sizeof to ensure that the correct value is passed
double y = Mean(d, ( sizeof (d) / sizeof (d[0])) - 1) ;
// use macro in sysopen.h
double z = Mean(d, ARRAYSIZE(d) - 1) ;
メモ: 上記の例と似ていますが、Object Pascal 関数が var パラメータを取る場合には、C++ 関数宣言のパラメータは
const
にはなりません。
要素数の計算
sizeof()、ARRAYSIZE マクロ、EXISTINGARRAY マクロのいずれかを使用して配列の要素数を計算する場合は、配列へのポインタを使用しないように注意してください。代わりに、次のように配列名そのものを渡します。
double d[] = { 3.1, 4.4, 5.6 } ;
int n = ARRAYSIZE(d); // sizeof (d)/ sizeof (d[0]) => 24/8 => 3
double *pd = d;
int m = ARRAYSIZE(pd); // sizeof (pd)/ sizeof (pd[0]) => 4/8 => 0 => Error !
配列の("sizeof" で得られる)サイズとポインタの("sizeof" で得られる)サイズは同じではありません。たとえば、次のような宣言がある場合、
double d[3];
double *p = d;
次のように配列のサイズを求める場合は、
sizeof (d) / sizeof d[0]
次のようにポインタのサイズを求める場合とは異なる評価結果になります。
sizeof (p) / sizeof (p[0])
上記とこの後の例では、sizeof() 演算子ではなく ARRAYSIZE マクロを使用しています。ARRAYSIZE マクロの詳細については、オンライン ヘルプを参照してください。
一時配列
Object Pascal では、無名の一時オープン配列を関数に渡すことができます。C++ には、そのための構文はありません。ただし、変数定義を他のステートメントと混在させることができるため、単に変数に名前を付けるというアプローチが可能です。
Delphi の場合:
Result := Mean([3.1, 4.4, 5.6]);
C++ の場合(名前付き "一時配列" を使用):
double d[] = { 3.1, 4.4, 5.6 } ;
return Mean(d, ARRAYSIZE(d) - 1) ;
名前付き "一時配列" のスコープを限定して、他のローカル変数と競合しないようにするには、次のように、新しいスコープを適切な位置に開きます。
long double x;
{
double d[] = { 4.4, 333.1, 0.0 } ;
x = Mean(d, ARRAYSIZE(d) - 1) ;
}
別の解決策については、「OPENARRAY マクロ」を参照してください。
array of const
Object Pascal では、"array of const" という言語構文要素をサポートしています。この引数型は、TVarRec のオープン配列を値で受け取るのと同じです。
以下は、array of const を受け取るように宣言された Object Pascal コード断片です。
function Format( const Format: string ; Args: array of const ): string ;
C++ では、プロトタイプは次のようになります。
UnicodeString __fastcall Format( const UnicodeString Format ,
TVarRec const *Args, const int Args_Size) ;
この関数の呼び出しは、次のように、オープン配列を引数に取る他のあらゆる関数と同様です。
void show_error ( int error_code, UnicodeString const &error_msg)
{
TVarRec v[] = { error_code, error_msg } ;
ShowMessage(Format("%d: %s", v, ARRAYSIZE(v) - 1)) ;
}
OPENARRAY マクロ
オープン配列を値で受け取る関数に一時オープン配列を渡す場合、名前付き変数を使用する代わりに、sysopen.h に定義されている OPENARRAY マクロを使用することもできます。
このマクロは次のように使用します。
OPENARRAY(T, (value1, value2, value3)) // up to 19 values
ここで、T は作成するオープン配列の型で、値パラメータはその配列の要素として使用されます。値引数を囲むかっこは必須です。次に例を示します。
void show_error(int error_code, UnicodeString const &error_msg)
{
ShowMessage(Format("%d: %s", OPENARRAY(TVarRec, (error_code, error_msg))));
}
OPENARRAY マクロを使用する際には、値を最大 19 個まで渡すことができます。それより大きい配列が必要な場合は、明示的な変数を定義しなければなりません。そのうえ、OPENARRAY マクロを使用すると、ベースとなる配列の割り当てコストと各値の追加コピーのために、実行時コストが(わずかながら)増えます。
コード サンプル
EXISTINGARRAY マクロ
sysopen.h に定義されている EXISTINGARRAY マクロを使用すると、オープン配列が必要な状況で既存の配列を渡すことができます。
このマクロは次のように使用します。
long double Mean( const double *Data, const int Data_Size) ;
double d[] = { 3.1, 3.14159, 2.17128 } ;
Mean(EXISTINGARRAY (d)) ;
メモ: セクション「要素数の計算」の内容は EXISTINGARRAY マクロにも当てはまります。
オープン配列引数を取る C++ 関数
Object Pascal のオープン配列を渡される C++ 関数を作成する際には、"値渡し" のセマンティクスを明示的に維持することが重要です。特に、関数の宣言が "値渡し" に相当する場合は、要素を変更する前に必ずそれを明示的にコピーするようにしてください。Object Pascal では、オープン配列は組み込み型であり、値渡しが可能です。C++ では、オープン配列型はポインタを使って実装されるため、ローカル コピーを作成しない限り、元の配列が変更されます。
配列を返す Object Pascal 関数
Object Pascal では、関数は配列を返すことができますが、C++ ではできません。この違いを調整するため、配列(たとえば T[1..n]
など)を返す Object Pascal メソッドについては、StaticArray<T, n>
のインスタンスを返すようにプロトタイプ宣言します。