[ Marko Medojević @ 12.07.2008. 13:29 ] @
Ćao!

Jasna mi je razlika između vrednosnih i referentnih tipova, tj. da vrednosni čuvaju svoju vrednost na stacku, dok referencijalni čivaju memorijsku lokaciju koja ukazuje na heap.
Standardan način za kreiranje vrednosnih tipova je:
Code:
int i;
bool j;
double x;

Dok se referentni kreiraju sa new():
Code:
int[] i = new int[5];
StreamWriter sw = new StreamWriter();


Interesuje me koja je razlika kad se vrednosni tipovi kreiraju sa new():
Code:
int i = new int();

Radio sam neke primere gde sam kreirao vrednosni tip sa new() i on se i dalje ponašao kao vrednosni tip što se vidi iz ovog primera:
Code:

int i = new int();
i = 5;
int j = i;
j = 10;
Console.WriteLine(i);

Naravno rezultat je 5 jer i i j ne ukazuju na istu lokaciju u memoriji već imaju zasebne vrednosti.
Pitanje je da li postoji neka začkoljica u ovom drugom primeru ili je potpino isto:
Code:
int i;

i
Code:
int i = new int();

?
[ mmix @ 12.07.2008. 14:22 ] @
Nema razlike u vidu skladistenja, value tipovi su "povlasceni" u smislu kreiranj koda i kompajler ih tretira drugacije od referentnih tipova i konstruktor value tipa nema isti efekat kao konstruktor referentnog tipa i ne podleze OOP pravilima. Jedino sto postizes sa new int() je da kompajler odmah dodeli default vrednost int-u tako da su zaprvo sledece dve instrukcije ekvivalentne:

Code:

int x = 0;
int x = new int();




[Ovu poruku je menjao mmix dana 12.07.2008. u 15:47 GMT+1]
[ Shadowed @ 12.07.2008. 14:54 ] @
Hm, pa int i; ja svakako dovoljno, i posle toga ce imati default vrednost. New nije potreban.
[ Marko Medojević @ 12.07.2008. 15:09 ] @
Hvala!
Sve mi je sad jasno.
[ mmix @ 12.07.2008. 15:09 ] @
Nece, stvar semantike, CLR specifikacija ne navodi da deklaracija value tipa blankuje njen adresni prostor, samo blokira pristup istom dok ga korisnik ne inicijalizuje (Use of unassigned local variable 'x'); do trenutka inicijalizacije promenljiva ima onu vrednost koja se zadesila na toj stek lokaciji u tom trenutku (jedino sto ne mozes da je iscitas), sa new int(); ili sa = 0; obavljas eksplicitnu inicijalizaciju i resetovanje promenljive. Probaj sledeci kod:

Code:

            int y = 0;
            Console.Write(y);
            int c = new int();
            Console.Write(c);
            int x;
            Console.Write(x);


x ce puci.
[ Shadowed @ 12.07.2008. 15:32 ] @
Hmm, nije hteo ni da kompajlira, medjutim (ono to sam i probao pre mog prethodnog posta), ako izbacim liniju koja koristi promenljivu, a stavim brakepoint negde kasnije, prilikom debug-a pokazuje da je x=0.

Inace, u vb.net-u ista varijanta prolazi - sledeci kod ispisuje nulu:
Code:

Dim i As Integer
Console.Write(i)
[ mmix @ 12.07.2008. 15:51 ] @
To je zato sto VB.NET odmah inicijalizuje polje, c# to ne radi, inicijalizaciju obavlja u momentu prve dodele, sto je mozda malo optimizovanije jer nece biti dve dodele . Svojevremeno sam se nesto petljao sa ovim pa nisam uspeo da nadjem u CLR specifikaciji da je obaveza JIT-a da blankuje [ESP+] prostor gde su value tipovi, mada JIT implementacija na Windows-u to radi na bootstraperu metode i za [ESP] promenljive i za promenljive koje drzi u registrima, tako da je sve ovo moot point dok god se drzis Windoza i .NETa; mozda jedino postane problem ako koristis unsafe metode na drugim platformama.

Code:

00000007  xor         eax,eax 
00000009  mov         dword ptr [esp],eax 
0000000c  mov         dword ptr [esp+4],eax  

[ mmix @ 12.07.2008. 16:13 ] @
Ok, mislim da znam zasto to rade, ne zbog C# ili VB.NET-a vec zbog IL-a, u njemu mozes komotno da napravis sledeci kod:

Code:
    .entrypoint
    .maxstack 1
    .locals init (int32 num)
    ldloc.0 
    call void [mscorlib]System.Console::WriteLine(int32)
    ret 


sto je ekvivalentno koriscenju neinicijalizovane varijable u C#-u
Code:

int num;
Console.WriteLine(num)


ukoliko JIT ne bi blankovao num na pocetku zaista bi dobio nepredvidive rezultate na konzoli. Pitam se kako ovaj IL prolazi na ostalim CLR platformama.
[ mmix @ 12.07.2008. 16:24 ] @
Ok, izvinjavam se na broju poruka, ali konacno sam mu doakao, ipak nije u JIT specifikaciji kao sto sam i pretpostavljao, fora je u kompajleru (mozda je u tehnickoj specifikaciji kompajlera, treba pogledati), kljuc se vrti oko "init" parametra .local JIT instrukcije. Ako nema init, nema ni blankovanja lokalnih varijabli u bootstrap-u. Dakle sledeci IL kod ispisuje random vrednosti lokalne promenljive u zavisnosti od toga sta je trenutno u steku/registru (gde god JIT ubaci lokalnu varijablu):

Code:
    .entrypoint
    .maxstack 1
    .locals (int32 num)
    ldloc.0 
    call void [mscorlib]System.Console::WriteLine(int32)
    ret


Izlaz:

C:\Temp001>ilasm /exe dirtyapp.il

Microsoft (R) .NET Framework IL Assembler. Version 2.0.50727.1434
Copyright (c) Microsoft Corporation. All rights reserved.
Assembling 'dirtyapp.il' to EXE --> 'dirtyapp.exe'
Source file is ANSI

Assembled method DirtyApp.Program::Main
Assembled method DirtyApp.Program::.ctor
Creating PE file

Emitting classes:
Class 1: DirtyApp.Program

Emitting fields and methods:
Global
Class 1 Methods: 2;

Emitting events and properties:
Global
Class 1
Writing PE file
Operation completed successfully

C:\Temp001>dirtyapp
1650720

C:\Temp001>dirtyapp
1126432

C:\Temp001>dirtyapp
1060896



Ko hoce nek isproba sam, zakacen je IL fajl.