Поделиться через


Семантика стека C++ для ссылочных типов

До Visual Studio 2005 экземпляр ссылочного типа можно создать только с помощью new оператора, который создал объект в мусорной куче. Однако теперь можно создать экземпляр ссылочного типа, используя тот же синтаксис, который будет использоваться для создания экземпляра собственного типа в стеке. Таким образом, вам не нужно использовать ссылку на новый, gcnew для создания объекта ссылочного типа. И когда объект выходит из области, компилятор вызывает деструктор объекта.

Замечания

При создании экземпляра ссылочного типа с семантикой стека компилятор внутренне создает экземпляр в сборке мусора (с помощью gcnew).

Если тип подписи или возвращаемого типа функции включает экземпляр ссылочного типа по значению, функция будет помечена в метаданных как требующая специальной обработки (с модреком). Эта специальная обработка в настоящее время предоставляется только клиентами Visual C++; Другие языки в настоящее время не поддерживают использование функций или данных, использующих ссылочные типы, созданные с семантикой стека.

Одна из причин использования gcnew (динамическое выделение) вместо семантики стека будет, если тип не имеет деструктора. Кроме того, использование ссылочных типов, созданных с семантикой стека в сигнатурах функций, невозможно, если вы хотите, чтобы функции использовались языками, отличными от Visual C++.

Компилятор не создаст конструктор копирования для ссылочного типа. Таким образом, если вы определяете функцию, использующую ссылочный тип по значению в сигнатуре, необходимо определить конструктор копирования для ссылочного типа. Конструктор копирования для ссылочного типа имеет подпись следующей формы: R(R%){}

Компилятор не создаст оператор назначения по умолчанию для ссылочного типа. Оператор назначения позволяет создавать объект с помощью семантики стека и инициализировать его с помощью существующего объекта, созданного семантикой стека. Оператор назначения для ссылочного типа имеет сигнатуру следующей формы: void operator=( R% ){}

Если деструктор типа освобождает критически важные ресурсы и используете семантику стека для ссылочных типов, вам не нужно явно вызывать деструктор (или вызов delete). Дополнительные сведения о деструкторах в ссылочных типах см. в разделе "Деструкторы и методы завершения" в статье "Практическое руководство. Определение и использование классов и структур (C++/CLI)".

Оператор назначения, созданный компилятором, будет соответствовать обычным стандартным правилам C++ со следующими дополнениями:

  • Любые нестатические члены данных, тип которых является дескриптором ссылочного типа, будут неглубоко скопированы (рассматриваются как нестатический член данных, тип которого является указателем).

  • Любой нестатический элемент данных, тип которого является типом значения, будет неглубоко скопирован.

  • Любой нестатический член данных, тип которого является экземпляром ссылочного типа, вызовет вызов конструктора копирования ссылочного типа.

Компилятор также предоставляет % унарный оператор для преобразования экземпляра ссылочного типа, созданного с помощью семантики стека в базовый тип дескриптора.

Для использования с семантикой стека недоступны следующие ссылочные типы:

Пример

Description

В следующем примере кода показано, как объявить экземпляры ссылочных типов с семантикой стека, как работает оператор назначения и конструктор копирования, а также как инициализировать ссылку на отслеживание с использованием ссылочного типа, созданного с семантикой стека.

Код

// 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);
}

Выходные данные

98
98
98
13
13

См. также

Классы и структуры