pin_ptr (C++/CLI)
声明固定指针,此指针仅适用于公共语言运行时。
所有运行时
(此语言功能没有适用于所有运行时的备注。)
Windows 运行时
(Windows 运行时不支持此语言功能。)
公共语言运行时
固定指针是一个内部指针,可防止指向的对象在垃圾回收堆上移动。 也就是说,公共语言运行时不会更改固定指针的值。 向未托管的函数传递托管类的地址时,必须使用此指针,这样地址就不会在解析未托管的函数调用过程中意外更改。
语法
[cli::]pin_ptr<cv_qualifiertype>var = &initializer;
参数
cv_qualifier
const
或 volatile
限定符。 在默认情况下,固定指针为 volatile
。 将固定指针声明为 volatile
虽是多余做法,但并不是错误做法。
type
初始值设定项的类型。
var
pin_ptr 变量的名称。
initializer
可以分配给本机指针的引用类型、托管数组的元素或者任何其他对象的成员。
备注
pin_ptr 表示本机指针的功能超集。 因此,可以分配给本机指针的所有内容也可以分配给 pin_ptr。 内部指针允许执行与本机指针相同的操作,其中包括比较和指针算法。
可以固定托管类的对象或子对象,在这种情况下,公共语言运行时不会在垃圾回收期间移动它。 它的主要用途是,将指向托管数据的指针作为未托管的函数调用的实际参数进行传递。 在回收周期内,运行时会检查为固定指针创建的元数据,但不会移动它指向的项。
固定一个对象还会固定它的值字段,即基元类型或值类型的字段。 不过,不会固定通过跟踪句柄 (%
) 声明的字段。
固定在托管对象中定义的子对象具有固定整个对象的效果。
如果将固定指针重新分配为指向新值,指向的旧实例就不再视为固定。
对象只有在 pin_ptr 指向它时才会固定。 如果对象的固定指针超出范围或设置为 nullptr,对象就不再固定。 在 pin_ptr 超出范围后,垃圾回收器可以在堆中移动之前固定的对象。 任何仍指向此对象的本机指针都不会进行更新,如果取消引用其中一个指针,可能会抛出不可恢复的异常。
如果没有固定指针指向对象(所有固定指针都超出了范围、重新分配为指向其他对象,或分配有 nullptr),那么对象保证不会固定。
固定指针可以指向引用句柄、值类型或装箱类型句柄、托管类型的成员或托管数组的元素。 但无法指向引用类型。
获取指向本机对象的 pin_ptr 的地址会导致未定义的行为发生。
固定指针只能声明为堆栈上的非静态本地变量。
固定指针无法用作:
函数参数
函数的返回类型
类成员
强制转换的目标类型。
pin_ptr 位于 cli
命名空间中。 有关详细信息,请参阅平台默认 cli 命名空间。
若要详细了解内部指针,请参阅 interior_ptr (C++/CLI)。
有关固定指针的详细信息,请参阅如何:固定指针和数组以及如何:声明固定指针和值类型。
要求
编译器选项:/clr
示例
下面的示例使用 pin_ptr 来约束数组中第一个元素的位置。
// pin_ptr_1.cpp
// compile with: /clr
using namespace System;
#define SIZE 10
#pragma unmanaged
// native function that initializes an array
void native_function(int* p) {
for(int i = 0 ; i < 10 ; i++)
p[i] = i;
}
#pragma managed
public ref class A {
private:
array<int>^ arr; // CLR integer array
public:
A() {
arr = gcnew array<int>(SIZE);
}
void load() {
pin_ptr<int> p = &arr[0]; // pin pointer to first element in arr
int* np = p; // pointer to the first element in arr
native_function(np); // pass pointer to native function
}
int sum() {
int total = 0;
for (int i = 0 ; i < SIZE ; i++)
total += arr[i];
return total;
}
};
int main() {
A^ a = gcnew A;
a->load(); // initialize managed array using the native function
Console::WriteLine(a->sum());
}
45
下面的示例展示了,可以将内部指针转换为固定指针,并且当操作数位于托管堆上时,取址器运算符 (&
) 的返回类型是内部指针。
// pin_ptr_2.cpp
// compile with: /clr
using namespace System;
ref struct G {
G() : i(1) {}
int i;
};
ref struct H {
H() : j(2) {}
int j;
};
int main() {
G ^ g = gcnew G; // g is a whole reference object pointer
H ^ h = gcnew H;
interior_ptr<int> l = &(g->i); // l is interior pointer
pin_ptr<int> k = &(h->j); // k is a pinning interior pointer
k = l; // ok
Console::WriteLine(*k);
};
1
下面的示例展示了可以将固定指针强制转换为其他类型。
// pin_ptr_3.cpp
// compile with: /clr
using namespace System;
ref class ManagedType {
public:
int i;
};
int main() {
ManagedType ^mt = gcnew ManagedType;
pin_ptr<int> pt = &mt->i;
*pt = 8;
Console::WriteLine(mt->i);
char *pc = ( char* ) pt;
*pc = 255;
Console::WriteLine(mt->i);
}
8
255