Datové typy

3. díl - Datové typy

Tomáš Herceg       05.05.2009       C#, VB.NET, .NET       22605 zobrazení

V tomto díle se podrobně podíváme na datové typy v .NET frameworku, vysvětlíme si rozdíl mezi typy hodnotovými a referenčním ia podíváme se pořádně, jak funguje zásobník a halda.

V minulém díle tohoto seriálu jsme si vysvětlili základní syntaktické konstrukce jazyků Visual Basic .NET a C#. Dnes si podrobněji popovídáme o datových typech v .NETu.

Datové typy

Nyní už k samotným datovým typům - .NET Framework rozlišuje mezi dvěma druhy typů – hodnotovými a referenčními. Rozdíl mezi nimi je dosti důležitý a jeho pochopení je pro další práci klíčové.

Adresní prostor procesu

Každý proces, který je v systému spuštěn, má tzv. adresní prostor. Při jakékoliv práci s pamětí se odvolává na konkrétní místa pomocí adresy, což je nějaké číslo. Na 32-bitovém operačním systému, které jsou dnes nejčastější, má každý proces 4GB velký adresní prostor, který může využívat (ve skutečnosti to bývá méně, ale to není podstatné). Neznamená to, že by systém každému procesu přidělil 4GB paměti, tolik paměti nemá. Tento adresní prostor je totiž jen virtuální a skutečná paměť se přidělí až v okamžiku, kdy proces danou část adresního prostoru využije. Operační systém pak překládá  tyto virtuální adresy (ty, které používá proces) na adresy ve skutečné paměti, dlouho nepoužívané bloky (stránky) odkládá na disk a když jsou potřeba, tak je zase načte zpět.

V adresovém prostoru je kromě celého kódu programu a různých dalších věcí také zásobník (stack) a halda (heap). Ty se používají pro ukládání dat a režijních informací.

Zásobník (stack)

Zásobník se používá pro ukládání lokálních proměnných metod a návratových adres. Pokud zavoláme metodu A a předáme jí nějaké parametry, na konec zásobníku se předá návratová adresa (adresa, odkud se metoda zavolala) a hodnoty všech parametrů, které se metodě předaly. Metoda A pak na konec zásobníku ještě přidá své lokální proměnné a provede svůj kód.

Navíc může třeba zavolat metodu B, čímž se opět na konec zásobníku přidá návratová adresa, předané parametry a lokální proměnné metody B. Jakmile metoda B skončí, proměnné i parametry se zruší, na zásobník se uloží návratová hodnota metody (výsledek volání funkce) a pokračuje se od návratové adresy v provádění metody A. Po jejím skončení se opět data ze zásobníku odeberou atd.

Následující ilustrace ukazuje zásobník a jeho změny během volání metody B z metody A. Je to samozřejmě trochu zjednodušené. Červeně vyznačený je řádek, který se zatím neprovedl. Datům na zásobníku, které patří nějaké konkrétní metodě, se také někdy říká aktivační záznam.

image[25]      image[24]

image[28]      image[35]

image[32]

Je vidět, že když z metody A zavolám sebe samotnou (rekurze), tak nové volání metody A bude mít vlastní lokální proměnné. Na zásobníku se pro druhé zavolání A vytvoří vlastní aktivační záznam.

Pokud uděláte nekonečnou rekurzi (z metody A budete vždy volat A znovu), zásobník se za chvíli zaplní a .NET Framework vyvolá StackOverflowException. To je průšvih a ve většině případů tím aplikace skončí.

Halda (heap)

Na zásobník můžeme ukládat pouze položky, které mají předem známou velikost (už v době kompilace). Navíc tyto položku musí být dostatečně malé. Pokud bychom na zásobník ukládali například pole hodnot, které má desítky kilobajtů, tak při předání tohoto pole kamkoliv jinam (jako parametr do nějaké metody, přiřazení do jiné proměnné atd.) by se musela celá tato obluda kopírovat. To je samozřejmě velmi neefektivní a zbytečné, i když jednou za čas to také je potřeba.

Navíc bychom nemohli udělat metodu, která něco vyrobí a dá to k dispozici všem ostatním – po vyskočení z metody se její lokální proměnné zruší a výše jsme si řekli, že globální proměnné nemáme. Jediný způsob, jak to vrátit, by bylo pomocí návratové hodnoty, kde bychom zase měli několik kopírování. Zásobník tedy evidentně nestačí. Proto máme kromě něj ještě haldu. Halda je takové chytřejší úložiště, které si na začátku zarezervuje určitou paměť a umí ji přerozdělovat pro různé účely.

V praxi když tedy najednou potřebujeme na uložení něčeho příkladně 100 bajtů (což se můžeme dovědět až za běhu aplikace), na haldě se vyhradí volné místo o velikosti 100 bajtů (často o trochu více, kvůli efektivitě se totiž bloky často dorovnávají na nějaký násobek osmi nebo šestnácti atp.). Nám se vrátí pouze adresa začátku tohoto bloku a tu si pak uložíme do lokální proměnné v metodě, se kterou pracujeme. Tomu se říká pointer (ukazatel), v .NET Frameworku používáme spíše pojmu reference, ale je to víceméně totéž. Je to mnohem rychlejší, protože pole sedí na haldě a pokud jej chceme někam předat, předáme jen maličkou (na 32bitové architektuře 4bajtovou) adresu, která je malá a krásně může ležet na zásobníku. Více proměnných nám může ukazovat na stejné pole, pokud pole změníme, změna se projeví v obou proměnných.

Jakmile data na haldě již nejsou potřeba, v aplikacích psaných v C/C++ musíme dát pomocí speciálního příkazu pokyn k uvolnění této naalokované paměti, jinak by nám tam zůstala viset, mohli bychom na ni ztratit ukazatel a už by se nikdy nedala odalokovat. Protože na haldě se postupně přidává a odebírá i z prostřed, vznikají v ní díry a kusy volného místa. Při požadavku na přidělení kusu paměti je tedy třeba volné místo hledat, což zabere nějaký čas.

V .NETu za nás uvolňování paměti obstarává Garbage Collector, který to dělá jednou za čas (když je paměť potřeba) a po větších dávkách. Haldu potom sesype dohromady, takže díry zmizí a hledání volného místa je pak nesrovnatelně rychlejší – vždycky se přidává na konec, uprostřed haldy žádné volné místo není. Obtížnější je to uvolňování paměti a zjišťování, která paměť již není potřeba. Sesypávání haldy je dost náročná operace (klidně to může trvat stovky milisekund) a obnáší to, aby GC prošel všechny reference a změnil jejich hodnoty, protože objektům se může měnit adresa. Tato operace je časově náročná a aplikace je během provádění garbage collection pozastavena.

Větší bloky dat je rozhodně lepší ukládat na haldu, jejich předávání do parametrů či proměnných je velmi efektivní (předává se jen maličká adresa), pomocí této adresy se s daty dá velmi snadno manipulovat a o uvolnění se nemusíme starat, špinavou práci za nás odvede někdo jiný. Proměnná obsahuje jen adresu, ne samotná data. V jazycích C# a VB.NET s ní pracujeme ale úplně stejně, jako kdyby obsahovala přímo nějaká data.

Ve skutečnosti halda nebývá jedna, ale může jich být i více, jedna na malé objekty, jedna na velké atd.

Hodnotové typy

Otázkou je, proč jsme si zde složitě vysvětlovali, co je to halda a co je to zásobník. K pochopení rozdílu mezi hodnotovými a referenčními typy je to nezbytné.

Hodnotové typy se vždy ukládají na místě, kde se používají. Pokud máme lokální proměnnou hodnotového typu, hodnota této proměnné se ukládá přímo na zásobníku. Pokud se jedná o proměnnou, která je uvnitř nějaké třídy na haldě, je uložena přímo v paměťové oblasti dané instance této třídy, a tedy na haldě.

Jak to vypadá na zásobníku a na haldě?

Hodnotové typy mají konstantní předem známou velikost, měly by být malé a vždy obsahují přímo hodnotu.

image[38]

Hodnotových typů je v .NET Frameworku několik stovek, používáme je dnes a denně a patří sem především primitivní hodnotové typy, struktury a výčtové typy.

Primitivní hodnotové typy

Hodnotovými typy jsou datové typy uvedené v této tabulce (byla již v minulém díle, ale pro úplnost ji zde opakuji).

VB.NET C# .NET typ Velikost Popis
SByte sbyte System.SByte 8 bitů 8-bit celé číslo se znaménkem (-128 až 127)
Byte byte System.Byte 8 bitů 8-bit celé číslo bez znaménka (0 až 255)
Short short System.Int16 16 bitů 16-bit celé číslo se znaménkem (-2^15 až 2^15 - 1)
UShort ushort System.UInt16 16 bitů 16-bit celé číslo bez znaménka (0 - 2^16 – 1)
Integer int System.Int32 32 bitů 32-bit celé číslo se znaménkem (-2^31 až 2^31 – 1)
UInteger uint System.UInt32 32 bitů 32-bit celé číslo bez znaménka (0 - 2^32 – 1)
Long long System.Int64 64 bitů 64-bit celé číslo se znaménkem (-2^63 až 2^63 – 1)
ULong ulong System.UInt64 64 bitů 64-bit celé číslo bez znaménka (0 - 2^64 – 1)
Single float System.Single 32 bitů 32-bit desetinné číslo podle IEEE 754 (7-8 platných cifer)
Double double System.Double 64 bitů 64-bit desetinné číslo podle IEEE 754
Decimal decimal System.Decimal 128 bitů 128-bit desetinné číslo (uložené po desítkových cifrách, menší zaokrouhlovací odchylky)
Boolean bool System.Boolean   hodnoty true / false
Char char System.Char 16 bitů 16-bit znak podle Unicode
- - System.IntPtr 32/64 bitů Pointer (kvůli práci s Windows API)

V jakémkoliv programovacím jazyce můžete pro datové typy použít název ze sloupce .NET typ, pokud si naimportujete jmenný prostor System, nemusíte uvádět celý název. V jazyce VB.NET můžete používat i názvy z 1. sloupce, v C# zase názvy z 2. sloupce (a také se to tak v drtivé většině případů píše, jsou to aliasy pro dané datové typy, aby se alespoň se základními typy pracovalo pohodlně).

Struktury (struct)

Struktura je komplexní datový typ, který sdružuje několik proměnných a může nad sebou definovat určité metody. Struktury se nepoužívají příliš často a je vhodné je používat pouze pro malá seskupení několika proměnných. Typickým příkladem užití je například reprezentace dvojice či vektoru:

Kód v jazyce Visual Basic .NET
    Structure Vector
        Public x As Double
        Public y As Double
    End Structure
Kód v jazyce C#
    struct Vector
    {
        public double x;
        public double y;
    }

Dovnitř struktury také můžeme přidat konstruktor nebo metody, o tom ale až později. Použití takového vektoru uvnitř metody může vypadat třeba takto:

Kód v jazyce Visual Basic .NET
            Dim v As Vector
            v.x = 15
            v.y = 1.4677
Kód v jazyce C#
            Vector v;
            v.x = 15;
            v.y = 1.4677;

Proměnná v je lokální v nějaké metodě, na zásobníku tedy bude uloženo 2 * 64 bitů, protože jedna proměnná typu double má právě 64 bitů.

 Struktura na zásobníku

Výčtové typy (enum)

Výčtové typy se používají pro zpřehlednění, jedná se víceméně o pojmenované sady konstant. Pokud bychom měli například proměnnou, v níž bude uchováván stav nějaké operace, můžeme si udělat konvenci, že stav 0 je nezahájeno, stav 1 znamená, že akce probíhá a stav 2 znamená, že byla akce dokončena, ale po čase člověk zapomene, co je co, a proto jsou výčtové typy k nezaplacení. Pokud neřekneme jinak, je hodnota výčtového typu interně reprezentována typem int.

Kód v jazyce Visual Basic .NET
    Enum Status
        NotStarted = 0
        Processing = 1
        Finished = 2
    End Enum
Kód v jazyce C#
    enum Status
    {
        NotStarted = 0,
        Processing = 1,
        Finished = 2
    }

Hodnoty jednotlivých konstant nemusíme uvádět, pokud je nespecifikujeme, vygenerují se samy. Použití výčtového typu je jednoduché. Všimněte si, že můžeme přiřadit hodnotu proměnné již při její deklaraci.

Kód v jazyce Visual Basic .NET
Dim s As Status = Status.Finished

Kód v jazyce C#
Status s = Status.Finished;

Referenční typy

Referenční typy se vždy ukládají na haldě a do proměnných se ukládá vždy pouze tzv. reference, což je ve skutečnosti adresa v paměti, kde jsou data uložena. Je nutné si uvědomit, že pokud do jedné proměnné přiřadíme referenční typ a pak obsah první proměnné přiřadíme do proměnné druhé, nikdy se nebudou kopírovat data samotného objektu. Proměnná drží pouze adresu v paměti, kopíruje se tedy pouze ta adresa. Dvě proměnné pak budou odkazovat na stejná data. Pokud data změníme přes jednu proměnnou, změna bude vidět i z druhé proměnné.

Více proměnných ukazující na stejnou třídu

Data referenčního typu se z haldy mohou odstranit až v okamžiku, kdy na ně není v žádné proměnné reference.

image[41]

Třída (class)

Třída je ve skutečnosti velmi podobná struktuře, ovšem hlavním rozdílem je, že je to referenční typ. Pokud by vektor z příkladu u struktur nebyla struktura, ale třída, ony dvě proměnné typu double by se uchovávaly na haldě, přičemž na zásobníku by byla (jakožto hodnota proměnné v) jen adresa, kde data na haldě leží. Kromě toho se ještě na haldě uloží nějaké dodatečné informace k identifikaci datového typu atd., takže zabrané paměti bude o ještě trochu více. Pro vektor není třída zrovna vhodný příklad, ale ukážeme si na něm ještě něco.

Kód v jazyce Visual Basic .NET
    Class Vector
        Public x As Double
        Public y As Double
    End Class
Kód v jazyce C#
    class Vector
    {
        public double x;
        public double y;
    }

Při použití v metodě pak narazíme na jednu věc – pokud změníme nějakou položku přes proměnnou v2, projeví se to i v proměnné v. To by s hodnotovými typy nešlo, každý by totiž měl svoji vlastní hodnotu. U referenčních typů je hodnota společná.

Kód v jazyce Visual Basic .NET

            Dim v As Vector = New Vector()
            v.x = 15
            v.y = 1.4677
            Dim v2 As Vector = v   ' kopírují se jen adresy
            v2.y = 15
            ' ve v.y bude také 15, data proměnných v a v2 jsou společná
Kód v jazyce C#
            Vector v = new Vector();
            v.x = 15;
            v.y = 1.4677;
            Vector v2 = v;  // kopírují se jen adresy
            v2.y = 15;
            // ve v.y bude také 15, data proměnných v a v2 jsou společná

Proměnné referenčního typu mohou mít také speciální hodnotu Nothing (VB.NET) resp. null (C#). Ta říká, že v proměnné není nic, je tam vlastně nulová adresa.

Pokud vytvoříme proměnnou hodnotového typu, nemusíme se o nic starat – v proměnné již bude připravená hodnota, místo v paměti se vyhradí automaticky. U proměnné referenčního typu se ale vyhradí místo jen pro referenci, pokud chceme vytvořit datovou položku, musíme použít klíčové slovo new. Tím zavoláme tzv. konstruktor, což je speciální metoda, která zajišťuje vytvoření a inicializaci datové položky.

Pokud bychom do proměnné v nic nepřiřadili, ukázka by se nezkompilovala, protože kompilátor požaduje, aby se do proměnné přiřadilo před jejím prvním použitím.

Pokud by v proměnné v byla hodnota Nothing, resp. null, a zavolali bychom v.x = 15, nastala by chyba, protože interně by se sáhlo do paměti na adresu, na kterou nemáme povoleno přistupovat, a runtime by nám vyhodil chybu, ale o tom až někdy příště.

Tím, že nadeklarujeme v a přiřadíme do ní new Vector(), se zajistí, že se na haldě vytvoří nová datová položka, která bude obsahovat dvě proměnné typu double, a adresa na tuto položku se uloží do proměnné v. Pak můžeme s v pracovat obdobně jako se strukturou.

Poznámka: pokud programujete v C++, je nutné si uvědomit, že v C++ se struktury a třídy chovají velmi podobně – chovají se jako hodnotové typy a abychom třídu donutili chovat se “kulturně”, musíme s ní pracovat pomocí pointerů. V .NETu jsou všechny třídy automaticky referenční a všechny struktury hodnotové. Při předávání hodnoty do metody se předává vždy obsah proměnné (tzn. u hodnotových typů data, u referenčních reference).

Problém je, že v .NETu nelze mezi hodnotovou a referenční formou přecházet tak jednoduše jako v C++, kde prostě někam předáte referenci na třídu, která leží třeba na zásobníku (samozřejmě jen pokud máte jistotu, že tam bude po celou dobu používání té reference). Naopak velmi jednoduše se v .NETu díky Garbage Collectoru řeší problém, kdy metoda má vrátit nějaký objekt (a chceme jej vrátit bez kopírování). V .NETu stačí pouze napsat něco jako return new Vector() a s instancí třídy Vector můžete vesele pracovat, v C++ se musíte postarat minimálně o to, aby to také někdo dealokoval, což se často řeší tak, že se prostě objekt vrací hodnotou, tím pádem se to kopíruje. díky tomu to ale odalokuje automaticky standardní mechanismus C++, protože kopie bude uložena na zásobníku. V C++ se odalokovávají ručně jen věci na haldě.

Dědičnost

Třídy v .NET Frameworku na rozdíl od struktur podporují dědičnost. Není podporována vícenásobná dědičnost, ale ona zas až tak moc v praxi není potřeba, resp. dá se bez ní obejít. Místo ní jsou podporována rozhraní.

Rozhraní (interface)

Rozhraní je lidově řečeno šablona pro to, co má třída umět. Rozhraní obsahuje seznam metod, vlastností a dalších položek, které musí třída, která toto rozhraní implementuje, obsahovat. Je nutné si uvědomit, že rozhraní neobsahuje žádný kód, jen hlavičky metod, ne jejich těla. Nemůže obsahovat ani proměnné, veškerou logiku a funkčnost musí zařídit třída.

.NET Framework vnitřně používá rozhraní na mnoha místech, pomocí nich například definuje porovnávání a mnoho dalších věcí.

Delegát (delegate)

Delegát je něco jako ukazatel na metodu, používá se pro dynamické volání metod.

O třídách, rozhraních, delegátech a dědičnosti si budeme více povídat v příštím díle tohoto seriálu.

Pole (array)

Pole jsou referenčním typem hlavně z toho důvodu, že mohou obsahovat velké počty položek a tím pádem většinou zabírají hodně místa. Obecně máme několik možností, jak s poli pracovat.

Jednorozměrné pole

Jednorozměrné pole je jednoduše tvořeno položkami naskládanými za sebou. Položky se indexují vždy od 0, není jiná možnost (ani ve Visual Basicu).

image[48]

Kód v jazyce Visual Basic .NET
Dim p1(2) As Integer
Kód v jazyce C#
int[] p1 = new int[3];

Všimněte si, že zde se již syntaxe dost podstatně liší. Ve VB.NET jako rozměr pole udáváme horní mez (tedy nejvyšší index, který je ještě platný). V C# naopak udáváme počet položek (tedy první index, který již platný není).

Vícerozměrné pole

Obyčejné vícerozměrné pole může mít více rozměrů. Každý rozměr je opět indexován od nuly. Výhodou je snadné použití pro obdélníkové (resp. kvádrové) oblasti dat.

image[51]

Kód v jazyce Visual Basic .NET
Dim p2(2, 2) As Integer
Kód v jazyce C#
int[,] p2 = new int[3,3];

Vícerozměrná pole jsou pohodlná na používání, ovšem jsou o trochu pomalejší než tzv. jagged arrays, totiž pole polí.

Jagged array

Pole polí je trochu těžší na vytvoření, nejprve je totiž třeba vytvořit pole referencí na jednotlivá pole. Výhodou je rychlost a efektivita v případě, že např. každý řádek není stejně dlouhý.

image[54]

Kód v jazyce Visual Basic .NET
Dim p3(2)() As Integer
For i As Integer = 0 To 2
    ReDim p3(i)(2)
Next
Kód v jazyce C#
int[][] p3 = new int[3][];
for (int i = 0; i < 3; i++)
    p3[i] = new int[3];

V prvním řádku se vytvoří pole integerových polí (na obrázku to pole, ze kterého vedou šipky). Pak se v cyklu projde každá položka tohoto pole a přiřadí se do ní nové pole (na obrázku to vodorovné).

Jagged arrays jsou o malinko efektivnější než vícerozměrná pole, ale je s nimi víc práce.

Přístup k položkám pole

K položkám pole přistupujeme podobně, jak pole deklarujeme. První řádek přistupuje k položkám prvního pole (jednorozměrného), druhý řádek přistupuje k položce druhého (vícerozměrného) pole a třetí řádek přistupuje k jagged array. Ve VB.NET se indexy uvádí do kulatých závorek, v C# do hranatých.

Kód v jazyce Visual Basic .NET
p1(0) = 1;
p2(0, 0) = 1;
p3(0)(0) = 1;
Kód v jazyce C#
p1[0] = 1;
p2[0, 0] = 1;
p3[0][0] = 1;

Závěrem

V tomto díle jsme si spíše teoreticky popsali některé datové typy. V příštích dílech si vysvětlíme, jak pracovat s dědičností a s rozhraními.

 

hodnocení článku

3 bodů / 3 hlasů       Hodnotit mohou jen registrované uživatelé.

 

Všechny díly tohoto seriálu

7. Rozhraní 19.07.2010
6. Dědičnost - dokončení 01.01.2010
5. Dědičnost 09.09.2009
4. Třídy 09.06.2009
3. Datové typy 05.05.2009
2. Základní elementy VB.NET a C# 18.04.2009
1. Úvod do .NET Frameworku 03.04.2009

 

 

 

Nový příspěvek

 

v článku vypadly obrázky

v článku vypadly obrázky

http://www.dotnetportal.cz/clanek/127/Da...

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Nefunguji obrazky

dobry den,

jsem strasne vdecny za clanek, bohuzel se mne spravne nezobrazuji obrazky ( misto toho se zobazi napr.: image [51] ), stalo se mne to uz na vice strankach toho (dobreho :) ) webu, v prubehu nejake doby, coz mne prijde skoda. Myslim, ze chyba nebude u me tak jen upozornuji ( popripadne pomocna odpoved snad pomuze popripadne i ostatnim :) )

pouzivam dnesni nejnovejsi verzi Firefoxu s W8

preji hezky den

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Datové typy

Dobrý den, přestože je tento článek již postarší, třeba mi někdo odpoví.. V článku je uvedeno: "Pokud se jedná o proměnnou, která je uvnitř nějaké třídy na haldě, je uložena přímo v paměťové oblasti dané instance této třídy, a tedy na haldě." Mám si to tedy vyložit tak, že v .NETu jsou na zásobníku jen proměnné a hodnotové typy ze statických tříd, které nemají svou instanci uloženu na haldě?

Díky za případnou odpověď.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Datové typy

Nedá mi to, abych, byť po mnoha letech od vzniku této série, za ní nepoděkoval a nepochválil. Moc se mi líbí, že je vše velice jasně a zároveň stručně popsáno, bez zbytečného balastu nicneříkajících slov, a zároveň bez tendence sklouzávat k nesrozumitelnosti, či přehnané náročnosti na čtenáře.

Jedním slovem paráda.

Díky!

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Datové typy

Ve 3. dílu, v části "Přístup k položkám pole" (před závěrem), jsou v ukázce kodu pro VB.NET

za každým příkazem přebytečné středníky. Asi nepozornost při kopírování :-)

Jinak díky moc za tento seriál, každí díl mi mnoho nového přinesl.

Přeji mnoho zdaru.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Diskuse: Datové typy

Pokud vytvořím nějaký objekt měl bych na konci práce s objektem jeho instanci zrušit? Čili měl bych ke každému new mít v kódu set objekt=Nothing?

dim objekt as new Osoba
...
...
set objekt=Nothing

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Někdy je vhodné to udělat (ale to set se tam ve VB.NET už nepíše), ale jsou to spíš specifické případy. O tohle se stará Garbage Collector, jakmile na objekt již neexistuje žádná reference, GC ho časem odstaní. To je dost složitý proces a určitě se o něm zmíním v dalších dílech tohoto seriálu.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

keď použijem

1 dim objekt as new Osoba

2 ...

3 objekt=Nothing

tak sa objekt (3 riadok) ihneď (pri vykonaní 3 riadka) vymaže z pamäte? T.j. používam vo VB .NET tray ikonu a chcem, keď v kontextovom menu ikony kliknem na "ukončiť program", aby ikona ihneď zmizla. Ona zmizne, ale až za chvíľu (alebo keď na ňu dám myš). Čítal som že GC je nedeterministický, teda nikdy sa nedá určiť kedy sa objekt zruší (ale ja chcem ikonu vyhodiť (zmazať) ihneď! Ako na to?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Ne, objekt se odstraní z paměti až časem, v okamžiku, kdy se spustí Garbage Collector.

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět

Vlastní smazání ikony, bych řešil

s pomocí nastavení její viditelnosti, tedy pokud je podporována vlastnost

object.visible = False,

či něco podobného.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Datové typy

Zdravím, potřeboval bych pomoc jedním problémem. V své aplikaci používám funkci umístěnou v dll knihovně. Jeden z parametrů, této knihovny je typu VOID a přes tento parametr se předává několik různých datových struktur.

Pokud funkci deklaruji takto:

Public Declare Function profi_snd_req_res Lib "papi.dll" (ByRef pSdb As T_PROFI_SERVICE_DESCR, ByRef pData As Object, ByRef Dummy As Long) As Integer

, tedy VOID nahradím typem OBJECT, při volání této funkce se mi pak objeví chybová hláška, že hodnota nespadá do očekávaného rozsahu rozsahu.

Nevíte prosím jak tento problém vyřešit?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Datové typy

Ahoj, v úvodním odstavci o haldě máš napsáno "Na zásobník můžeme ukládat pouze položky, které mají předem známou velikost (už v době kompilace)." . Podlě mě to není pravda, na tom jsem se shodl i s vzučujícím profesorem na Katedře indofmatiky v Olomouci. Podle mě to velikost musíš přeci znát u každé položky, kterou ukládáš. Navíc si v tom odstavci celkem protiřečíš.

Jinak děkuju za články, jsou zajímavé, ale na zkoušku se z nich už asi učit nebudu ;-)

nahlásit spamnahlásit spam 0 odpovědětodpovědět

V článku je to správně, špatně jste to pochopil. Mluvím o tom, že velikost musí být známa v době kompilace, což u zásobníku platí, velikost všech hodnotových typů je pevná.

Naproti tomu u referenčních typů to neplatí - mějme typ Osoba, která má v sobě dva integery, velikost bude tedy 8 bajtů + režijní záznam. Když z tohoto typu podědíme třeba typ Zamestnanec a přidáme mu další 2 integery, velikost bude 16 bajtů + režijní data. Pokud zanedbáme režijní data (jsou pořád stejně velká, obsahují např. informaci o zámku a datovém typu položky; na zásobníku nejsou), tak velikost položky je různá, což haldě nevadí. Jistěže za běhu se ví, kolik bajtů je potřeba naalokovat, ale za kompilace ne.

Osoba o;
// nějaký kód
o = new Zamestnanec();

Komplátor neví, jak velká bude položka uložená v osobě, pokud by ji dal, na zásobníku by to vědět měl.

Tak je tomu i v C++, i když to tak na první pohled nevypadá. Tam sice můžete uložit instanci objektu na zásobník, ale vezme se prostě velikost typu Osoba a pokud tam uložíme instanci typu Zamestnanec, dojde k tzv. slicingu, data z třídy Zamestnanec se oříznou, aby se do Osoby vešly, což samozřejmě nechceme. Pokud chceme, aby se to v C++ chovalo korektně, musíme použít ukazatel na objekt. V .NETu je to jakoby implicitní - pokud jde o třídu, proměnné se samy chovají jako ukazatele, kdyby to byla struktura, tak by tento problém nastal, jenže struktury v .NETu dědičnost nepodporují.

Doufám, že jsem to vysvětlil lépe, i na daném místě v tom článku píšu de facto to samé. A kde si tam protiřečím? Nějak to v tom nevidím.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Podle vaší odpovědi vidím, že tomu rozumíte, asi jsem to tedy jen špatně pochopil z toho textu. Tím pádem to že si protiřečíte beru zpět.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Datové typy

Ahoj,

v deklaraci pole polí máš malou chybku.

Dim p3(2)() As Integer
For i As Integer = 0 To 2
    ReDim p3(i)(2)
Next

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Jasně, díky moc.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Datové typy

A úroveň týchto stránok stúpa :-)

Ďakujem!

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback