Foo **
どのような状況で、C ++で複数の間接参照(つまり、のようなポインターのチェーン)を使用したいですか?
8 に答える
@aku が指摘した最も一般的な使用法は、関数が戻った後にポインター パラメーターへの変更を表示できるようにすることです。
#include <iostream>
using namespace std;
struct Foo {
int a;
};
void CreateFoo(Foo** p) {
*p = new Foo();
(*p)->a = 12;
}
int main(int argc, char* argv[])
{
Foo* p = NULL;
CreateFoo(&p);
cout << p->a << endl;
delete p;
return 0;
}
これは印刷されます
12
ただし、次の例のように、文字列の配列を反復処理して標準出力に出力する、他にもいくつかの便利な使用法があります。
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
const char* words[] = { "first", "second", NULL };
for (const char** p = words; *p != NULL; ++p) {
cout << *p << endl;
}
return 0;
}
IMOの最も一般的な使用法は、ポインター変数への参照を渡すことです。
void test(int ** var)
{
...
}
int *foo = ...
test(&foo);
ダブルポインタを使用して、多次元のジャグ配列を作成できます。
int ** array = new *int[2];
array[0] = new int[2];
array[1] = new int[3];
一般的なシナリオの1つは、関数にnullポインターを渡し、その関数内で初期化して、関数外で使用する必要がある場合です。複数の間接参照がないと、呼び出し元の関数は初期化されたオブジェクトにアクセスできません。
次の関数について考えてみます。
initialize(foo* my_foo)
{
my_foo = new Foo();
}
'initialize(foo *)'を呼び出す関数は、Fooの初期化されたインスタンスにアクセスできません。これは、この関数に渡されるポインターがコピーであるためです。(ポインタは結局のところ単なる整数であり、整数は値によって渡されます。)
ただし、関数が次のように定義されている場合:
initialize(foo** my_foo)
{
*my_foo = new Foo();
}
...そしてそれはこのように呼ばれました...
Foo* my_foo;
initialize(&my_foo);
...次に、呼び出し元は「my_foo」を介して初期化されたインスタンスにアクセスできます。これは、「initialize」に渡されたポインタのアドレスであるためです。
もちろん、私の単純化した例では、「initialize」関数はreturnキーワードを介して新しく作成されたインスタンスを返すことができますが、それは必ずしも適切ではありません。関数は別のものを返す必要があるかもしれません。
出力パラメーターとしてポインターを渡す場合は、ポインターをとして渡し、Foo**
その値をとして設定することをお勧めします*ppFoo = pSomeOtherFoo
。
また、アルゴリズムとデータ構造の部門では、その二重間接参照を使用してポインターを更新できます。これは、たとえば実際のオブジェクトを交換するよりも高速です。
簡単な例はint** foo_mat
、整数の2次元配列として使用することです。または、ポインターへのポインターを使用することもできます-ポインターがありvoid* foo
、次のメンバーでそれを参照する2つの異なるオブジェクトがあるとします。void** foo_pointer1
そしてvoid** foo_pointer2
、ポインターへのポインターを使用することで、どちら*foo_pointer1 == NULL
がfooはNULLです。foo_pointer1が通常のポインターである場合、fooがNULLであるかどうかを確認することはできません。私の説明があまり乱雑ではなかったことを願っています:)
通常、戻り値として関数へのポインターを渡す場合:
ErrorCode AllocateObject (void **object);
ここで、関数は成功/失敗のエラー コードを返し、オブジェクト パラメーターに新しいオブジェクトへのポインターを入力します。
*object = new Object;
これは、Win32 での COM プログラミングでよく使用されます。
これは C で行うべきことです。C++ では、多くの場合、このタイプのシステムをクラスにラップして、コードを読みやすくすることができます。
カール: あなたの例は次のようになります。
*p = x;
(あなたには 2 つの星があります。) :-)
C では、イディオムは絶対に必要です。char * へのポインタの配列に文字列 (純粋な C なので char *) を追加する関数が必要な問題を考えてみましょう。関数プロトタイプには、3 つのレベルの間接化が必要です。
int AddStringToList(unsigned int *count_ptr, char ***list_ptr, const char *string_to_add);
次のように呼びます。
unsigned int the_count = 0;
char **the_list = NULL;
AddStringToList(&the_count, &the_list, "The string I'm adding");
C++ では、代わりに参照を使用するオプションがあり、別のシグネチャが生成されます。ただし、元の質問で尋ねた 2 つのレベルの間接化が必要です。
int AddStringToList(unsigned int &count_ptr, char **&list_ptr, const char *string_to_add);