ポインタ

種類

  • マネージド ポインタ (managed pointers) … 共通言語ランタイムのヒープから、メモリのマネージド ブロックへの参照 (CLS準拠の新しいポインタ)
  • アンマネージド ポインタ (unmanaged pointers) … 標準C++のヒープから、メモリのアンマネージド ブロックを参照 (従来型のC++ポインタ)
  • アンマネージド関数ポインタ (unmanaged function pointers) … 関数のアドレスを参照 (従来型のC++ポインタ。CLS準拠の関数ポインタとしてデリゲートがある)

interior_ptr (内部ポインタ)

オブジェクト自身ではなく、その内部へのポインタを宣言できます。

cli::interior_ptr<cv_qualifier type> var = &initializer;
interior_ptr | MSDN
ref class MyClass
{
public:
    int a;
};

int main()
{
    MyClass^ myClass = gcnew MyClass();
    myClass->a = 1;

//               int* p = &(myClass->a); // error C2440: '初期化中': 'cli::interior_ptr<int>' から 'int *' に変換できません。
    interior_ptr<int> p = &(myClass->a);

    (*p)++; // myClass->a は2となる
}

アンマネージド ポインタはガベージコレクションによってインスタンスのマネージド ヒープ上での位置が変更されると追跡できず、内部ポインタはそれを解決する仕組みです。

pin_ptr (固定ポインタ)

固定ポインタは、ガベージコレクションによってアドレスが変更されるのを防ぐ内部ポインタです。

[cli::]pin_ptr<cv_qualifier type> var = &initializer;
pin_ptr (C++/CLI) | MSDN

これは次のように、アンマネージド ポインタを受け取る関数に、マネージド型のポインタを渡すような場合に利用できます。

void Increment(int* p)
{
    (*p)++;
}

int main()
{
    Int32 n1 = 10;
    pin_ptr<Int32> p1 = &n1; // 値n1への参照をコピー

    int* p = p1; // 固定ポインタのアドレスは、アンマネージド ポインタへコピーできる

    Increment(p1);
    // n1とp1は11になる


    Int32^ n2 = gcnew Int32(10);
    pin_ptr<Int32> p2 = &*n2; // 参照n2への参照をコピー

    Increment(p2);
    // *n2とp2は11になる


    Int32 n = *n2;          // 参照n2の値をnへコピー
    pin_ptr<Int32> p3 = &n; // 値nへの参照をコピー

    Increment(p3);
    // *n2は11のまま、nとp3は12になる

    return 0;
}

また「error C2664: '***': 引数 1 を 'cli::interior_ptr<type *>' から 'type **' へ変換できません。」としてエラーとなる場合も、

pin_ptr<type*> p = &a;

のように取得したポインタを渡すことで解決できます。c++ cli - Convert from C++/CLI pointer to native C++ pointer - Stack Overflow

pin_ptrで宣言されたオブジェクトのスコープが外れると、それが指し示すポインタの固定も解除されます。

参考

参考書

nullptr (nullポインタ)

オブジェクトを示さないオブジェクト ハンドル、内部ポインタまたはアンマネージド ポインタの値を表現できます。このキーワードはマネージドおよびアンマネージドの型に対して用いられますが、コンパイラはそれぞれ異なるコードを生成します。

参考

Microsoft Learnから検索