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