Semantyka stosu języka C++ dla typów odwołań
Przed programem Visual Studio 2005 wystąpienie typu odwołania można utworzyć tylko przy użyciu new
operatora , który utworzył obiekt na stercie zbieranym przez śmieci. Teraz można jednak utworzyć wystąpienie typu odwołania przy użyciu tej samej składni, której można użyć do utworzenia wystąpienia typu natywnego na stosie. Dlatego nie trzeba używać metody ref new, gcnew , aby utworzyć obiekt typu odwołania. A gdy obiekt wykracza poza zakres, kompilator wywołuje destruktor obiektu.
Uwagi
Podczas tworzenia wystąpienia typu odwołania przy użyciu semantyki stosu kompilator wewnętrznie tworzy wystąpienie na stercie zbieranym przez śmieci (przy użyciu polecenia gcnew
).
Gdy typ podpisu lub zwracania funkcji zawiera wystąpienie typu odwołania by-value, funkcja zostanie oznaczona w metadanych jako wymagająca specjalnej obsługi (z modreq). Ta specjalna obsługa jest obecnie zapewniana tylko przez klientów języka Visual C++; inne języki nie obsługują obecnie korzystania z funkcji ani danych korzystających z typów referencyjnych utworzonych za pomocą semantyki stosu.
Jednym z powodów użycia gcnew
(alokacji dynamicznej) zamiast semantyki stosu byłoby, gdyby typ nie miał destruktora. Ponadto użycie typów odwołań utworzonych za pomocą semantyki stosu w podpisach funkcji nie byłoby możliwe, jeśli chcesz, aby funkcje zostały używane przez języki inne niż Visual C++.
Kompilator nie wygeneruje konstruktora kopii dla typu odwołania. W związku z tym, jeśli zdefiniujesz funkcję, która używa typu odwołania by-value w podpisie, musisz zdefiniować konstruktor kopii dla typu odwołania. Konstruktor kopiujący dla typu odwołania ma sygnaturę następującego formularza: R(R%){}
.
Kompilator nie wygeneruje domyślnego operatora przypisania dla typu odwołania. Operator przypisania umożliwia utworzenie obiektu przy użyciu semantyki stosu i zainicjowanie go przy użyciu istniejącego obiektu utworzonego przy użyciu semantyki stosu. Operator przypisania dla typu odwołania ma sygnaturę następującego formularza: void operator=( R% ){}
.
Jeśli destruktor typu zwalnia krytyczne zasoby i używasz semantyki stosu dla typów referencyjnych, nie musisz jawnie wywoływać destruktora (lub wywołać metody delete
). Aby uzyskać więcej informacji na temat destruktorów w typach referencyjnych, zobacz Destruktory i finalizatory w temacie How to: Define and consume classes and structs (C++/CLI) (Instrukcje: definiowanie i używanie klas i struktur (C++/CLI).
Operator przypisania generowanego przez kompilator będzie przestrzegał zwykłych standardowych reguł języka C++ z następującymi dodatkami:
Wszystkie niestatyczne składowe danych, których typ jest uchwytem typu odniesienia, zostaną skopiowane płytkie (traktowane jak niestatyczny element członkowski danych, którego typem jest wskaźnik).
Każdy niestatyczny element członkowski danych, którego typ jest typem wartości, zostanie skopiowany płytki.
Każdy niestatyczny element członkowski danych, którego typem jest wystąpienie typu odwołania, wywoła wywołanie konstruktora kopii typu odwołania.
Kompilator udostępnia %
również operator jednoargumentowy do konwertowania wystąpienia typu odwołania utworzonego przy użyciu semantyki stosu do jego bazowego typu dojścia.
Następujące typy referencyjne nie są dostępne do użycia z semantykami stosu:
Przykład
opis
Poniższy przykładowy kod przedstawia sposób deklarowania wystąpień typów referencyjnych za pomocą semantyki stosu, sposobu działania operatora przypisania i konstruktora kopiowania oraz inicjowania odwołania do śledzenia przy użyciu typu odwołania utworzonego przy użyciu semantyki stosu.
Kod
// stack_semantics_for_reference_types.cpp
// compile with: /clr
ref class R {
public:
int i;
R(){}
// assignment operator
void operator=(R% r) {
i = r.i;
}
// copy constructor
R(R% r) : i(r.i) {}
};
void Test(R r) {} // requires copy constructor
int main() {
R r1;
r1.i = 98;
R r2(r1); // requires copy constructor
System::Console::WriteLine(r1.i);
System::Console::WriteLine(r2.i);
// use % unary operator to convert instance using stack semantics
// to its underlying handle
R ^ r3 = %r1;
System::Console::WriteLine(r3->i);
Test(r1);
R r4;
R r5;
r5.i = 13;
r4 = r5; // requires a user-defined assignment operator
System::Console::WriteLine(r4.i);
// initialize tracking reference
R % r6 = r4;
System::Console::WriteLine(r6.i);
}
Wynik
98
98
98
13
13