2009-10-28 12 views
9

W .NET 4 beta 2 istnieje nowa przestrzeń nazw Numerics z struct BigInteger. documentation stwierdza, że ​​jest to typ niezmienny, jak bym się spodziewał.Czy BigInteger jest niezmienny czy nie?

Ale jestem trochę zdezorientowany przez operatora po inkrementacji (++). To zdaje się mutować wartość. Poniższy natomiast pętla działa:

static BigInteger Factorial(BigInteger n) 
{ 
    BigInteger result = BigInteger.One; 
    BigInteger b = BigInteger.One; 

    while (b <= n) 
    { 
     result = result * b; 
     b++; // immutable ? 
    } 
    return result; 
} 

To co MSDN ma do powiedzenia na temat operatora wzrostu ceny:

Ponieważ obiekty BigInteger są niezmienne, operator Przyrost tworzy nowy obiekt BigInteger którego wartość jest o jeden większy niż obiekt BigInteger reprezentowany przez wartość. Dlatego wielokrotne połączenia z inkrementacją mogą być drogie.

wszystko dobrze i dobrze, bym zrozumiał, gdybym musiał użyć b = b++ ale widocznie ++ sama w sobie jest na tyle, aby zmienić wartość.

Jakieś myśli?

Edytuj:
Jak wskazuje Lasse, istnieje step-by-step specification, jak działa post-increment. Ale nadal wydaje się, że jest to sprzeczne z niezmiennością. Na przykład nie mogę sobie wyobrazić, że używanie tego operatora jest bezpieczne dla wątków.

Odpowiedz

13

Operatorzy ++ i -- są realizowane w warunkach normalnych + i - operatorów, więc w rzeczywistości:

b++; 

odpowiada:

var temp = b; 
b = b + 1; 
<use temp for the expression where b++ was located> 

Teraz, jak skomentował to może wydaje się, że łamie niezmienność, ale tak nie jest.

Należy zamiast spojrzeć na ten kod, jak to zrobić:

var temp = b; 
b = BigInteger.op_Add(b, 1); // constructs a new BigInteger value 
<use temp ...> 

ten opuści dwa obiekty w pamięci, oryginalna wartość BigInteger, a nowy, teraz odwołuje b. Można łatwo sprawdzić, że to, co dzieje się z następującego kodu:

var x = b; 
b++; 
// now inspect the contents of x and b, and you'll notice that they differ 

Więc oryginalny obiekt nie uległ zmianie, stąd też nie łamie niezmienność i odpowiedzieć na nową część pytania, to powinien być wątek -bezpieczny.

To jest to samo, co dzieje się z ciągów:

String s1 = s2; 
s2 += "More"; 
// now inspect s1 and s2, they will differ 
+0

Brzmi rozsądnie, ale nadal wydaje się przełamać niezmienność. Będę trochę edytować pytanie. –

+1

Nie, to nie łamie niezmienności, pozwól mi zaktualizować odpowiedź. –

+2

W 's + = s2' widoczne jest zadanie. Pasuje, jeśli zaakceptujesz, że 'b ++' jest również zadaniem, tj. 'B = b + 1'. Ale '++' wciąż wydaje się/wygląda na mutację. –

3

Od BigInteger jest niezmienna, b ++ będzie tylko odpowiednik:

BigInteger temp=b; 
b=temp+1; 

Po tej operacji, temperatura jest zawracany przez GC a pamięć zostaje uwolniona.

+1

OK, z wyjątkiem części GC. Jest to struct (z wewnętrzną tablicą). –

+0

Tak, a jedyną różnicą jest to, że struktura jest przechowywana na stosie, podczas gdy ta klasa jest przechowywana w stercie. –

+0

Ted, gdzie, twoim zdaniem, przechowywane jest pole BigInteger w obiekcie? –