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 odśmiecanej pamięci. 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ć 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 Visual C++; inne języki nie obsługują obecnie używania funkcji ani danych korzystających z typów referencyjnych utworzonych za pomocą semantyki stosu.

Jedną z przyczyn użycia gcnew (alokacja dynamiczna) zamiast semantyki stosu jest to, że typ nie ma destruktora. Ponadto użycie typów odwołań utworzonych z 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 kopiującego dla typu referencyjnego. W związku z tym, jeśli zdefiniujesz funkcję, która używa typu odwołania by-value w podpisie, musisz zdefiniować konstruktor kopiujący dla typu odwołania. Konstruktor kopiujący dla typu odwołania ma podpis następującej formy: 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 podpis następującej formy: void operator=( R% ){}.

Jeśli destruktor typu zwalnia krytyczne zasoby i używasz semantyki stosu dla typów referencyjnych, nie trzeba 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).

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 do typu referencyjnego, zostaną skopiowane (traktowane jak niestatyczny element członkowski danych, którego typ jest wskaźnikiem).

  • 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, aby przekonwertować wystąpienie typu odwołania utworzonego przy użyciu semantyki stosu do jego podstawowego typu dojścia.

Następujące typy referencyjne nie są dostępne do użycia z semantykami stosu:

Przykład

Opis

Poniższy przykład kodu 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 za pomocą typu referencyjnego 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);
}

Dane wyjściowe

98
98
98
13
13

Zobacz też

Klasy i struktury