C # odpowiednik wektora C ++, z ciągłą pamięcią?

85

Jaki jest odpowiednik wektora C ++ w języku C #?

Szukam tej funkcji:

Aby mieć dynamiczną tablicę przechowywanej w sposób ciągły pamięci, która nie ma wpływu na wydajność dostępu w porównaniu ze standardowymi tablicami.

Szukałem i mówią .NET equivalent to the vector in C++ is the ArrayList, więc:

Czy ArrayList ma tę ciągłą funkcję pamięci?

edgarmtze
źródło
4
Czy CLR nie jest wystarczająco blisko metalu, abyś mógł określić (lub nawet konsekwentnie oczekiwać), w jaki sposób struktura jest alokowana w pamięci?
Aphex

Odpowiedzi:

101

Możesz użyć a, List<T>a kiedy Tjest typem wartości, zostanie on przydzielony w ciągłej pamięci, co nie miałoby miejsca, gdyby Tbył typem referencyjnym.

Przykład:

List<int> integers = new List<int>();
integers.Add(1);
integers.Add(4);
integers.Add(7);

int someElement = integers[1];
Darin Dimitrov
źródło
2
@cMinor, dokumentacja List<T>klasy zawiera wiele przykładów, ale zaktualizowałem moją odpowiedź, aby zawierała jeden.
Darin Dimitrov
5
Nie jestem w 100% zaznajomiony z CLR, ale ma sens, że nawet jeśli Tjest to typ referencyjny, nadal będziesz mieć ciągłą pamięć. Jest to w zasadzie tablica wskaźników ...
josaphatv
„co by nie miało miejsca, gdyby T jest typem referencyjnym” - tak samo jest w przypadku T[]... OP poprosił o „brak obniżenia wydajności w przypadku dostępu w porównaniu ze standardowymi macierzami” i List<T>zapewnia to. A jeśli Tjest typem referencyjnym, jest to analogiczne do T*w C ++, więc uzyskuje się tyle samo ciągłości, co w C ++. Jeśli chce się, aby same obiekty były ciągłe, to oczywiście potrzebne są typy wartości ... w obu językach. Różnica polega oczywiście na tym, że w C ++ każdy typ może być użyty jako value lub ref, podczas gdy w C # jest to właściwość typu poprzez rozróżnienie class / struct.
Jim Balter
Nauczyłem się czegoś dzisiaj. Myślałem, że List<T>zawsze jest implementowana jako lista połączona wewnętrznie. Jak więc dynamicznie się rozwija, gdy dzwonimy Add()? Coś w rodzaju VB6, Redim Preservektóre kopiowało całą tablicę do nowej lokalizacji?
dotNET,
@dotNet, wewnętrznie List<T>tworzy małą tablicę T[]. Elementy wewnętrznie są dodawane do tablicy. Gdy rozmiar tablicy jest zakończony, tworzona jest nowa tablica o podwójnym rozmiarze w stosunku do poprzedniej. Dane są kopiowane do nowej większej tablicy, mniejsza jest niszczona i tak dalej. Programista może dać wskazówkę NET w celu utworzenia wystarczająco dużego wewnętrzną tablicę przed napełnieniem List przez konstruktora: new List<T>(expected_array_size).
Artru
16

używać List<T>. Wewnętrznie używa tablic, a tablice używają ciągłej pamięci.

Bala R
źródło
2
Nie do końca prawda. Jeśli T jest typem referencyjnym, nie będzie ciągłej pamięci.
Matteo Mosca
2
@Matteo Jeśli spojrzysz na źródło, jest ono private T[] _items;używane do przechowywania na zapleczu, typu referencyjnego lub nie.
Bala R
13
Wiem o tym. Ale powiedz mi. Masz List <SomeClass>. Odwołania do instancji SomeClass będą przechowywane w ciągłej pamięci, ale nie same instancje. Jako typy referencyjne będą znajdować się w stercie i na pewno wiesz, jak działa sterta.
Matteo Mosca
@MatteoMosca przechowywanie referencji w sposób ciągły usuwa przynajmniej jeden poziom pośredni. Chyba lepiej niż nic.
Tim Seguine,
7
@MatteoMosca OP poprosił o „brak obniżenia wydajności dostępu w porównaniu ze standardowymi tablicami”. Tak jest w przypadku List <T> niezależnie od tego, jakie jest T, więc wszystkie twoje komentarze na tej stronie są nie na miejscu.
Jim Balter
16

Przede wszystkim trzymaj się z dala od Arraylistlub Hashtable. Te klasy należy uznać za przestarzałe, na korzyść typów ogólnych. Nadal są w języku dla celów starszych.

Teraz szukasz List<T>klasy. Zauważ, że jeśli T jest typem wartości, będziesz mieć pamięć contiguos, ale nie, jeśli T jest typem referencyjnym, z oczywistych powodów.

Matteo Mosca
źródło
15

C # ma wiele typów odwołań. Nawet jeśli kontener przechowuje odniesienia w sposób ciągły, same obiekty mogą być rozproszone po stercie

Armen Tsirunyan
źródło