Sdílet prostřednictvím


Sledování zpracování zabalené hodnoty

Použití sledovacího popisovače pro odkazování typu hodnoty se od spravovaných rozšíření jazyka C++ do Visual C++ 2010 změnilo.

Zabalení je typickým znakem systému sjednocených typů CLR. Typy hodnot přímo obsahují jejich stav, zatímco odkazové typy jsou implicitní pár: pojmenovaná entita je popisovač pro nepojmenovaný objekt, přidělený na spravované haldě. Jakákoli inicializace nebo přiřazení typu hodnoty do Object například vyžaduje, aby byl typ hodnoty umístěn v rámci haldy CLR – to je tam, kde vzniká bitová kopie zabalení – nejprve přidělením přidružené paměti a poté zkopírováním stavu typu hodnoty, a poté navrácením adresy tohoto anonymního hybrida Hodnoty/Odkazu. Proto, když člověk napíše v C#

object o = 1024; // C# implicit boxing

projevuje se další výhoda v podobě zjednodušení kódu. Návrh C# skrývá nejen složitost toho, co operace provádějí pod pokličkou, ale také abstrakce samotného zabalení. Na druhé straně spravovaná rozšíření jazyka C++, v rozčarování, že to povede k falešnému pocitu efektivity, to předkládají uživateli vyžadováním explicitních instrukcí:

Object *o = __box( 1024 ); // Managed Extensions explicit boxing

Zabalení je implicitní v Visual C++ 2010:

Object ^o = 1024; // new syntax implicit boxing

Klíčové slovo __box poskytuje zásadní službu v rámci spravovaných rozšíření, která chybí v návrhu jazyků jako je C# a Visual Basic: to poskytuje jak slovníkový tak sledovací popisovač pro přímou práci se zabalenou instancí na spravované haldě. Zvažte například následující malý program:

int main() {
   double result = 3.14159;
   __box double * br = __box( result );

   result = 2.7; 
   *br = 2.17;   
   Object * o = br;

   Console::WriteLine( S"result :: {0}", result.ToString() ) ;
   Console::WriteLine( S"result :: {0}", __box(result) ) ;
   Console::WriteLine( S"result :: {0}", br );
}

Základní kód, vygenerovaný pro tři vyvolání WriteLine, ukazuje různé ceny přístupu k hodnotě zabaleného typu hodnoty (díky Yves Dolce pro poukázání na tyto rozdíly), kde uvedené řádky ukazují režii, spojenou s každým vyvoláním.

// Console::WriteLine( S"result :: {0}", result.ToString() ) ;
ldstr      "result :: {0}"
ldloca.s   result  // ToString overhead
call       instance string  [mscorlib]System.Double::ToString()  // ToString overhead
call       void [mscorlib]System.Console::WriteLine(string, object)

// Console::WriteLine( S"result :: {0}", __box(result) ) ;
Ldstr    " result :: {0}"
ldloc.0
box    [mscorlib]System.Double // box overhead
call    void [mscorlib]System.Console::WriteLine(string, object)


// Console::WriteLine( S"result :: {0}", br );
ldstr    "result :: {0}"
ldloc.0
call     void [mscorlib]System.Console::WriteLine(string, object)

Předání zabaleného typu hodnoty přímo Console::WriteLine eliminuje jak zabalení tak potřebu volání ToString(). (Samozřejmě existuje dřívější zabalení pro inicializaci br, takže jsme nic nezískali, pokud opravdu vložíme br do práce.

V nové syntaxi je podpora pro zabalené typy hodnot podstatně více elegantní a integrovaná se systémem typů při zachování jejich síly. Zde je například překlad dřívějšího malého programu:

int main()
{
   double result = 3.14159;
   double^ br = result;
   result = 2.7;
   *br = 2.17;
   Object^ o = br;
   Console::WriteLine( "result :: {0}", result.ToString() );
   Console::WriteLine( "result :: {0}", result );
   Console::WriteLine( "result :: {0}", br );
}

Viz také

Úkoly

How to: Explicitly Request Boxing

Koncepty

Typy hodnot a jejich chování