Cómo: Usar referencias de seguimiento en C++/CLI
En este artículo se muestra cómo usar una referencia de seguimiento (%) en C++/CLI para pasar tipos de Common Language Runtime (CLR) por referencia.
Para pasar tipos de CLR por referencia
En el ejemplo siguiente se muestra cómo usar una referencia de seguimiento para pasar tipos de CLR por referencia.
// tracking_reference_handles.cpp
// compile with: /clr
using namespace System;
ref struct City {
private:
Int16 zip_;
public:
City (int zip) : zip_(zip) {};
property Int16 zip {
Int16 get(void) {
return zip_;
} // get
} // property
};
void passByRef (City ^% myCity) {
// cast required so this pointer in City struct is "const City"
if (myCity->zip == 20100)
Console::WriteLine("zip == 20100");
else
Console::WriteLine("zip != 20100");
}
ref class G {
public:
int i;
};
void Test(int % i) {
i++;
}
int main() {
G ^ g1 = gcnew G;
G ^% g2 = g1;
g1 -> i = 12;
Test(g2->i); // g2->i will be changed in Test2()
City ^ Milano = gcnew City(20100);
passByRef(Milano);
}
zip == 20100
En el ejemplo siguiente se muestra que tomar la dirección de una referencia de seguimiento devuelve interior_ptr (C++/CLI) y se muestra cómo modificar y acceder a los datos a través de una referencia de seguimiento.
// tracking_reference_data.cpp
// compile with: /clr
using namespace System;
public ref class R {
public:
R(int i) : m_i(i) {
Console::WriteLine("ctor: R(int)");
}
int m_i;
};
class N {
public:
N(int i) : m_i (i) {
Console::WriteLine("ctor: N(int i)");
}
int m_i;
};
int main() {
R ^hr = gcnew R('r');
R ^%thr = hr;
N n('n');
N %tn = n;
// Declare interior pointers
interior_ptr<R^> iphr = &thr;
interior_ptr<N> ipn = &tn;
// Modify data through interior pointer
(*iphr)->m_i = 1; // (*iphr)->m_i == thr->m_i
ipn->m_i = 4; // ipn->m_i == tn.m_i
++thr-> m_i; // hr->m_i == thr->m_i
++tn. m_i; // n.m_i == tn.m_i
++hr-> m_i; // (*iphr)->m_i == hr->m_i
++n. m_i; // ipn->m_i == n.m_i
}
ctor: R(int)
ctor: N(int i)
Referencias de seguimiento y punteros interiores
En el ejemplo de código siguiente se muestra que se puede realizar una conversión entre referencias de seguimiento y punteros interiores.
// tracking_reference_interior_ptr.cpp
// compile with: /clr
using namespace System;
public ref class R {
public:
R(int i) : m_i(i) {
Console::WriteLine("ctor: R(int)");
}
int m_i;
};
class N {
public:
N(int i) : m_i(i) {
Console::WriteLine("ctor: N(int i)");
}
int m_i;
};
int main() {
R ^hr = gcnew R('r');
N n('n');
R ^%thr = hr;
N %tn = n;
// Declare interior pointers
interior_ptr<R^> iphr = &hr;
interior_ptr<N> ipn = &n;
// Modify data through interior pointer
(*iphr)->m_i = 1; // (*iphr)-> m_i == thr->m_i
ipn->m_i = 4; // ipn->m_i == tn.m_i
++thr->m_i; // hr->m_i == thr->m_i
++tn.m_i; // n.m_i == tn.m_i
++hr->m_i; // (*iphr)->m_i == hr->m_i
++n.m_i; // ipn->m_i == n.m_i
}
ctor: R(int)
ctor: N(int i)
Referencias de seguimiento y tipos de valor
En este ejemplo se muestra una conversión boxing simple a través de una referencia de seguimiento a un tipo de valor:
// tracking_reference_valuetypes_1.cpp
// compile with: /clr
using namespace System;
int main() {
int i = 10;
int % j = i;
Object ^ o = j; // j is implicitly boxed and assigned to o
}
En el ejemplo siguiente se muestra que es posible tener referencias de seguimiento y referencias nativas a tipos de valor.
// tracking_reference_valuetypes_2.cpp
// compile with: /clr
using namespace System;
int main() {
int i = 10;
int & j = i;
int % k = j;
i++; // 11
j++; // 12
k++; // 13
Console::WriteLine(i);
Console::WriteLine(j);
Console::WriteLine(k);
}
13
13
13
En el ejemplo siguiente se muestra que se pueden usar referencias de seguimiento junto con tipos de valor y tipos nativos.
// tracking_reference_valuetypes_3.cpp
// compile with: /clr
value struct G {
int i;
};
struct H {
int i;
};
int main() {
G g;
G % v = g;
v.i = 4;
System::Console::WriteLine(v.i);
System::Console::WriteLine(g.i);
H h;
H % w = h;
w.i = 5;
System::Console::WriteLine(w.i);
System::Console::WriteLine(h.i);
}
4
4
5
5
En este ejemplo se muestra que cualquier referencia de seguimiento se puede enlazar a cualquier tipo de valor del montón recopilado por elementos no utilizados:
// tracking_reference_valuetypes_4.cpp
// compile with: /clr
using namespace System;
value struct V {
int i;
};
void Test(V^ hV) { // hv boxes another copy of original V on GC heap
Console::WriteLine("Boxed new copy V: {0}", hV->i);
}
int main() {
V v; // V on the stack
v.i = 1;
V ^hV1 = v; // v is boxed and assigned to hV1
v.i = 2;
V % trV = *hV1; // trV is bound to boxed v, the v on the gc heap.
Console::WriteLine("Original V: {0}, Tracking reference to boxed V: {1}", v.i, trV.i);
V ^hV2 = trV; // hv2 boxes another copy of boxed v on the GC heap
hV2->i = 3;
Console::WriteLine("Tracking reference to boxed V: {0}", hV2->i);
Test(trV);
v.i = 4;
V ^% trhV = hV1; // creates tracking reference to boxed type handle
Console::WriteLine("Original V: {0}, Reference to handle of originally boxed V: {1}", v.i, trhV->i);
}
Original V: 2, Tracking reference to boxed V: 1
Tracking reference to boxed V: 3
Boxed new copy V: 1
Original V: 4, Reference to handle of originally boxed V: 1
Plantillas de función que toman parámetros nativos, de valor o de referencia
Mediante el uso de una referencia de seguimiento en la firma de una plantilla de función, asegúrese de que un parámetro cuyo tipo sea nativo, valor CLR o referencia de CLR.
// tracking_reference_template.cpp
// compile with: /clr
using namespace System;
class Temp {
public:
// function templates
template<typename T>
static int f1(T% tt) { // works for object in any location
Console::WriteLine("T %");
return 0;
}
template<typename T>
static int f2(T& rt) { // won't work for object on the gc heap
Console::WriteLine("T &");
return 1;
}
};
// Class Definitions
ref struct R {
int i;
};
int main() {
R ^hr = gcnew R;
int i = 1;
Temp::f1(i); // ok
Temp::f1(hr->i); // ok
Temp::f2(i); // ok
// error can't track object on gc heap with a native reference
// Temp::f2(hr->i);
}
T %
T %
T &