Fórum Root.cz
Hlavní témata => Vývoj => Téma založeno: chobot 17. 02. 2014, 16:53:46
-
Dobrý den,
chtěl bych poprosit, jakým postupem(vodítky) jiným než pokus/omyl byste rozlišili, zda takové pole nebo struktura je ve zmíněném jazyce hodnotový nebo referenční typ.
Např. pole napíšu:
int[] ar = new int[5];
Teď když jsem použil new, čekal bych, že inty budou na haldě a měly by tam být už jen proto, že kdykoliv můžu zavolat Array.Resize(...). Znamená to ale, že je "ar" automaticky referenční typ, nebo v tom mám zmatek?
Podobně můžu mít strukturu
struct Struktura {...}
a můžu ji instanciovat buď jako
Struktura s1;
- to bych hledal na zásobníku jako hodnotový typ, ale zdá se mi, že můžu napsat také
Struktura s2 = new Struktura();
a tam bych čekal, že "s2" bude už na haldě.
Je, prosím, správné předjímat, že to, co vytvořím na haldě budou referenční typy? Snad vyjma toho, že součástí referenčního typu - např. proměnná typu int byť jako member instance třídy se samozřejmě referenčním typem nestane.
Jaké vodítko, prosím, používáte Vy?
Děkuji.
-
V c# to funguje inak ako v c++ vsetky bezne typy zacinajuce malym pismenom su hodnotove + k tomu este typ struct a union ostatne typy su referencne.
-
Máš nějaký důvod, proč to vůbec rozlišovat? V C# (Javě, smalltalku, ...) se dá v naprosté většině případů na všechny objekty koukat jako na reference, a to včetně například čísla 42 - když si představíš, že je to reference na něco, co se při používání chová jako číslo 42, nedokážeš to v žádném případě odlišit od samotné hodnoty čísla 42. Objekty se nikdy nekopírují, pokud se explicitně nezavolá nějaká metoda copy apod., vždy se jen kopírují reference, a když už nikdo žádnou referenci nedrží, objekt je uklizen garbage collectorem. C# není C++, a IMHO jediný případ, kdy má rozlišování hodnot od referencí smysl, je FFI - foreign function interface, volání C/C++ funkcí z C#, v C# se to myslím jmenuje unmanaged kód?, kdy se očekává konkrétní rozložení hodnot v paměti. Na zásobník v C# úplně zapomeň, klidně si představuj, že všechno je na haldě (resp. spravováno GC). Jazyky s garbage collectorem jsou jiné než C++, i když jejich název také začíná na C :)
-
Např. pole napíšu:
int[] ar = new int[5];
Teď když jsem použil new, čekal bych, že inty budou na haldě a měly by tam být už jen proto, že kdykoliv můžu zavolat Array.Resize(...). Znamená to ale, že je "ar" automaticky referenční typ, nebo v tom mám zmatek?
Mohou být na haldě a mohou být i na zásobníku, záleží, jestli to pole může opustit scope a jak to dokáže překladač optimalizovat. Pole jsou immutable, Array.Resize vyrobí nové pole.
Podobně můžu mít strukturu
struct Struktura {...}
a můžu ji instanciovat buď jako
Struktura s1;
- to bych hledal na zásobníku jako hodnotový typ, ale zdá se mi, že můžu napsat také
Struktura s2 = new Struktura();
a tam bych čekal, že "s2" bude už na haldě.
V C++ ano. V C# nemáte možnost ovlivnit, jestli se to tvoří na haldě nebo na zásobníku. (Tedy nějaká možnost tam asi je, ale normálně se to nepoužívá.)
Je, prosím, správné předjímat, že to, co vytvořím na haldě budou referenční typy? Snad vyjma toho, že součástí referenčního typu - např. proměnná typu int byť jako member instance třídy se samozřejmě referenčním typem nestane.
Jaké vodítko, prosím, používáte Vy?
Žádné. U jazyků s automatickou správou paměti to nemá smysl rozlišovat.
-
Voditko, ktere pouzivam ja, je dokumentace od MS: http://msdn.microsoft.com/en-us/library/s1ax56ch.aspx (http://msdn.microsoft.com/en-us/library/s1ax56ch.aspx) http://msdn.microsoft.com/en-us/library/490f96s2.aspx (http://msdn.microsoft.com/en-us/library/490f96s2.aspx)
Tedy, oba lide, co psali predtim, se myli. C# (a .NET) rozlisuje referencni a hodnotove typy (narozdil od Javy) - a treba u struct to hraje roli. Dale, string je referencni typ, prestoze se zapisuje malym pismenem. Jina vec je, ze C# dela autoboxing a tridy jako String, Array atd., ktere obsahuji metody aplikovatelne na tyto typy.
-
Voditko, ktere pouzivam ja, je dokumentace od MS: http://msdn.microsoft.com/en-us/library/s1ax56ch.aspx (http://msdn.microsoft.com/en-us/library/s1ax56ch.aspx) http://msdn.microsoft.com/en-us/library/490f96s2.aspx (http://msdn.microsoft.com/en-us/library/490f96s2.aspx)
Tedy, oba lide, co psali predtim, se myli. C# (a .NET) rozlisuje referencni a hodnotove typy (narozdil od Javy) - a treba u struct to hraje roli. Dale, string je referencni typ, prestoze se zapisuje malym pismenem. Jina vec je, ze C# dela autoboxing a tridy jako String, Array atd., ktere obsahuji metody aplikovatelne na tyto typy.
Java to rozlišuje také, akorát tomu říká třídy (ty jsou referencované) a primitivní typy (ty jsou předávané hodnotou). Nicméně na rozdíly mezi nimi narazíte jen při použití JNI. Ale struct (neprimitivní hodnotový typ) tedy nemá.
-
A jeste pro uplnost:
http://msdn.microsoft.com/en-us/library/9b9dty7d.aspx (http://msdn.microsoft.com/en-us/library/9b9dty7d.aspx)
"Typ array je referencni typ odvozeny od abstraktni bazove tridy typu Array."
-
Java to rozlišuje také, akorát tomu říká třídy (ty jsou referencované) a primitivní typy (ty jsou předávané hodnotou). Nicméně na rozdíly mezi nimi narazíte jen při použití JNI. Ale struct (neprimitivní hodnotový typ) tedy nemá.
Ja tohle vim, jen jsem chtel strucne polemizovat s tim, co napsal td.
-
Java to rozlišuje také, akorát tomu říká třídy (ty jsou referencované) a primitivní typy (ty jsou předávané hodnotou). Nicméně na rozdíly mezi nimi narazíte jen při použití JNI. Ale struct (neprimitivní hodnotový typ) tedy nemá.
Ja tohle vim, jen jsem chtel strucne polemizovat s tim, co napsal td.
OK, tohle jsem o C# nevěděl, omlouvám se za zmatení a díky za vyjasnění. Příště si dám větší bacha a budu opatrněji vyvozovat ze svých obecných zkušeností závěry pro jazyky, ve kterých jsem nikdy nepsal :)
-
Voditko, ktere pouzivam ja, je dokumentace od MS: http://msdn.microsoft.com/en-us/library/s1ax56ch.aspx (http://msdn.microsoft.com/en-us/library/s1ax56ch.aspx) http://msdn.microsoft.com/en-us/library/490f96s2.aspx (http://msdn.microsoft.com/en-us/library/490f96s2.aspx)
Tedy, oba lide, co psali predtim, se myli. C# (a .NET) rozlisuje referencni a hodnotove typy (narozdil od Javy) - a treba u struct to hraje roli. Dale, string je referencni typ, prestoze se zapisuje malym pismenem. Jina vec je, ze C# dela autoboxing a tridy jako String, Array atd., ktere obsahuji metody aplikovatelne na tyto typy.
string je referencny a vytvara sa na heape, ale sprava sa jak hodnotovy pretoze je immutable (kazda zmena hodnoty vracia novy objekt) takisto funguju typy ako Int32, Decimal, ... su referencne ale pri predavani treba pouzit ref.
int, decimal, doble (zacinajuce malym pismenom) ... su hodnotove. V jave to funguje +- podobne len tam je schyzofrenia s operatormi == a Equals.
Operator new je v .NET len na okrasu, v niektorych .NET jazykoch sa moze uplne vynechat.
-
Voditko, ktere pouzivam ja, je dokumentace od MS: http://msdn.microsoft.com/en-us/library/s1ax56ch.aspx (http://msdn.microsoft.com/en-us/library/s1ax56ch.aspx) http://msdn.microsoft.com/en-us/library/490f96s2.aspx (http://msdn.microsoft.com/en-us/library/490f96s2.aspx)
Tedy, oba lide, co psali predtim, se myli. C# (a .NET) rozlisuje referencni a hodnotove typy (narozdil od Javy) - a treba u struct to hraje roli. Dale, string je referencni typ, prestoze se zapisuje malym pismenem. Jina vec je, ze C# dela autoboxing a tridy jako String, Array atd., ktere obsahuji metody aplikovatelne na tyto typy.
string je referencny a vytvara sa na heape, ale sprava sa jak hodnotovy pretoze je immutable (kazda zmena hodnoty vracia novy objekt) takisto funguju typy ako Int32, Decimal, ... su referencne ale pri predavani treba pouzit ref.
int, decimal, doble (zacinajuce malym pismenom) ... su hodnotove. V jave to funguje +- podobne len tam je schyzofrenia s operatormi == a Equals.
Operator new je v .NET len na okrasu, v niektorych .NET jazykoch sa moze uplne vynechat.
C# neni Java! int je alias pro Int32 (http://msdn.microsoft.com/cs-cz/library/5kzh1b5w.aspx (http://msdn.microsoft.com/cs-cz/library/5kzh1b5w.aspx)).
Jinat trida Type ma property IsValueType, takze treba typeof(int).IsValueType. Ale az na nektere situace u generickych tipy si nedokazu predstavit, k cemu to clovek potrebuje vedet. Tohle je C# o pamet se stara GC a kompilator, lide vymysli algoritmy :)
-
Ono je potřeba to rozlišovat. Například, když se v C# píše unmanaged kód (klíčové slovo unsafe), tak se programátor hrabe v paměti úplně stejně jako v C/C++. Proto je minimálně v tomto případě dobré to rozlišovat. Nevím jestli Java umožňuje vkládat do managed kódu kusy kódu s přímým přístupem do paměti.
Obecně platí, že primitivní datové typy int, float, bool jsou hodnotové typy, stejně jako struct.
Třídy jsou referenční typy.
Klíčové slovo new nedělá nic jiného, než že vytvoří instanci daného typu v té části paměti, která odpovídá hodnotovým, nebo referenčním typům. Nic jiného.
Hodnotové typy se své podstaty hodí pro datové struktury s menší potřebou paměti. A je dobré uvažovat, kdy se co použije. zvlášť když má člověk použít nějaké kolekce (boxing, unboxing který žere čas a prostředky). Best practice zní: používat generické kolekce raději než nějaký array.
Shrnuto: Hodnotové typy pro menší objekty. Keyword new nemění místo v paměti. Brát to v úvahu při přímé práci s pamětí (jako v C/C++) a brát v úvahu boxing a unboxing.
Poznámka: Myslím, že jestli dnes někdo pokládá C# za Microsoft kopii Javy, tak opravdu hodně zaspal dobu.
-
V c# to funguje inak ako v c++ vsetky bezne typy zacinajuce malym pismenom su hodnotove + k tomu este typ struct a union ostatne typy su referencne.
Promiň ale to není správně. Rozdíl mezi Object a object není. Jsou to synonyma(i když je C# case sensitive). U důležitých tříd a struktur jsou podporována synonyma. Důvodu proč to tak je je hodně.
-
Jak clovek pozna jestli se jedna o typ s hodnotou predavanou odkazem (class) nebo s hodnotou predavanou hodnotou (struct) :) je celkem jednoduchy.
a) Dokumentace
b) Vyvojovy prostredi na ne maji v napovidani jinou ikonku
c) Porad dokola pouzivas par zakladnich typu takze si to zapamatujes
I pokud budes pouzivat usnafe kod (= ukazatele) je v podste jedno kde ti co lezi, dulezity je, ze se jinak chovaj pri pouziti = a predani jako parametru do funkce
A hlavne to potrebujes jenom v pripade, ze resis pouziti absurdne velkyho mnozstvi vlaken a nastavujes jim maly lokalni stacky.
int[] ar = new int[5];
Teď když jsem použil new, čekal bych, že inty budou na haldě a měly by tam být už jen proto, že kdykoliv můžu zavolat Array.Resize(...). Znamená to ale, že je "ar" automaticky referenční typ, nebo v tom mám zmatek?
Pole na cokoliv je vzdycky referencni typ odvozeny od System.Array je uplne jedno co do toho davas. Rozdil od c++ je v tom, ze Array je objekt = typ odvozenej od system.Object a ne jenom ukazatel na kus alokovany pameti = chova se jako vsechny ostatni classy.
struct Struktura {...}
a můžu ji instanciovat buď jako
Struktura s1;
- to bych hledal na zásobníku jako hodnotový typ, ale zdá se mi, že můžu napsat také
Struktura s2 = new Struktura();
a tam bych čekal, že "s2" bude už na haldě.
new Struktura() ber v podstate syntaktickej cukr. Je to tam kvuli tomu, ze Struktury muzou obsahovat "konstruktor" s parametrama pro snadnejsi inicializaci new Struktura(int, int, int) ( = proste metoda co nejak inicializuje hodnoty aniz bys to musel porad dokola psat struktura.x = 1; struktura.y=2 atd..). Takze kdyby to tam nebylo tak je to ponekud nekonzistentni chovani.
Je, prosím, správné předjímat, že to, co vytvořím na haldě budou referenční typy? Snad vyjma toho, že součástí referenčního typu - např. proměnná typu int byť jako member instance třídy se samozřejmě referenčním typem nestane.
Jaké vodítko, prosím, používáte Vy?
Děkuji.
No hlavne neni dobry predjimat to, ze si neco vytvoril na halde :). Proc povazujete za dulezite, jestli promenna lezi na halde nebo na stacku?
Ale funguje takhle:
1)"veci" o kterych kompilator vi kdy je muze smazat. Typicky lokalni promenne.
- tim padem se tam vykytuji reference na objekt a struktury
- ve chvili kdy vypadnete z metody stack se posune a tim je postarano o cisteni pameti
- u struktur se posunutim stacku uvolni vsechna pamet kterou zabiraji
- potom co se smaze reference na objekt zustavaji clensky data na heapu, pokud se to to nepostara GC (nebo finalizer)
2) "veci" o kterych kompilator nevi kdy jim konci platnost
- jsou na heape vzdycky. Vcetne struktur
Pokud to chcete brat z pohledu dat tak:
Na stacku jsou jenom struktury deklarovany jako lokalni promenne, nebo predane jako parametry funkce
vsechno ostani je na heapu
(Jinak na stacku jeste lezej reference na lokalni objekty)
Jenze se to chova prave takhle, protoze je to nejlepsi reseni na ktery kdo zatim prisel. U dalsi verze .NETu se klidne muzou rozhodnout davat maly classy taky na stack, nikdo nemuze zarucit, ze se to bude takhle chovat vzdycky .)