2012-06-29 11 views
14

Cóż, nie sądzę, że jest to naprawdę ważne, ale ponieważ program musi mimo wszystko przechowywać długość z powodu usunięcia [], dlaczego nie możemy uzyskać tych "przechowywanych informacji"?C++ dlaczego nie ma czegoś takiego jak length (array)?

+6

Bo tak mówi standard C++. –

+1

To nie jest prawdziwe pytanie, czy masz kod, o który pytasz? – trumpetlicks

+2

@trumpetlicks czemu nie? Uważam to za pytanie o funkcję językową. Przydatna może być znajomość motywacji. –

Odpowiedz

9

Implementacja wymaga tylko przechowywania długości, i zwykle robi to tylko wtedy, gdy typ nie jest trywialnie niszczalny (tj. musi generować wywołania do destruktora) a tablica została utworzona za pomocą nowego operatora [].

Ponieważ ta właściwość typu szeregowego nie ma żadnego związku z rozmiarem tablicy, bardziej elegancka jest po prostu wywołanie długości "cookie" jako prywatnego szczegółu implementacji.

Aby uzyskać długość kompletnego obiektu tablicy (nie tylko wskaźnika), można użyć std::extent< decltype(arr) >::value lub std::end(arr) - std::begin(arr).

Używanie new[] z klasą z destruktorem to zapach kodu. Zamiast tego należy rozważyć std::vector. Napowietrzne vs surowe new[] (biorąc pod uwagę wszystkie bajty, które należy przydzielić, gdziekolwiek się znajdują) to jedna wartość wskaźnika, a zalety są niezliczone.

+0

Dodaj do tego, że nie jest trudno uzyskać długość z tego, co zapewnia język, np. ze standardową implementacją szablonu. –

+1

W rzeczywistości narzut "wektora" to dwa wskaźniki (lub rozmiary), ponieważ musi on śledzić zarówno wielkość, jak i pojemność. +1 i tak. –

+0

@MikeSeymour Ale odejmij jeden wskaźnik narzutu, ponieważ ciasteczko "length" tablicy dynamicznej jest tak duże jak wskaźnik. – Potatoswatter

0

ponieważ jest to wdrożenie, w którym przechowuje te informacje. tak więc nie ma ogólnego sposobu wykonywania długości (tablica)

+8

'length (array)' może również należeć do implementacji. – Kos

1

Nie wszystkie tablice są przydzielane przez new.

void f(int* arr, size_t n) 
{ 
    length(arr); // ??? 
} 


int main() 
{ 
    int a[5]; 
    f(a); 
} 

To trywialne napisać choć, po prostu zadzwoń (std::end(arr) - std::begin(arr)), chociaż to działa tylko dla tablic, a nie wskaźniki, które wskazują na początku tablic.

+0

Stary trik '(sizeof (arr)/sizeof (* arr)) działa również dla prawdziwych tablic, ale podoba mi się nowy styl – stefaanv

+0

Odejmowanie iteratora nie może być (łatwo) zoptymalizowane do stałej. sizeof jest, ale jest mniej bezpieczny. 'szablon constexpr std :: size_t length (T (&) [N]) {return N; } 'jest bezpieczne i może zoptymalizować do stałej. –

+0

@JoeWreschnig, to nie są ogólne iteratory, są wskaźnikami, a różnica między dwoma adresami w tej samej tablicy może być zoptymalizowana do stałej. I zasugerowałem 'end-begin', ponieważ jest to trywialne, podczas gdy definiowanie tego szablonu funkcji nie jest trywialne, obejmuje niepoprawne parametry szablonu i brzydki deklarator tablicowy - nieodpowiedni dla początkujących! –

2

Rozważmy przypadek:

char* a = new char[100]; 

Teraz a potrzeby do punktu do bufora, który jest co najmniej 100 znaków duży, ale system mógłby przydzielić większy bufor do wypełnienia tej.

Mając to na uwadze, widzimy, że system może natychmiast zapomnieć o rozmiarze, o jaki prosił program, o ile nadal będzie mógł zwolnić bufor odpowiednio później. (Pamiętając o wielkości przydzielonego bufora lub wykonując przydział pamięci za pomocą inteligentnej struktury danych, w której wymagany jest tylko wskaźnik do początku)

Tak więc, w ogólnym przypadku informacja, której szukasz, to nie, w rzeczywistości przechowywany w dowolnym miejscu.

0

Długość z pewnością nie jest przechowywana na wszystkich implementacjach. C++ pozwala na przykład na zbieranie śmieci (np. Boehmgc), a wiele kolektorów nie musi znać długości. W tradycyjnych alokatorach przechowywana długość będzie często większa niż rzeczywista długość, tj. Przydzielona długość, a nie długość.

+2

Długość (liczba obiektów, nie bajtów) musi być gdzieś przechowywana, jeśli obiekty tablicy mają nietrywialne destruktory. Taki mechanizm jest przejrzysty dla alokatora, który ślepo przydziela niektóre bajty dopełnienia do implementacji. GC z obiektami innymi niż POD jest nową i przełomową funkcją. – Potatoswatter

+0

tak, ale to tylko podzbiór przypadków i mogę wymyślić sposoby uniknięcia przechowywania długości (np. Kluczy wartownika). –

+0

Nie jesteś pewien co masz na myśli. Czy chcesz używać bajtów dopełnienia dla wartownika? A co, jeśli nie ma dopełnienia? W każdym razie, wszystkie implementacje robią to w ten sam sposób, więc "nie przechowywane na wszystkich implementacjach" jest błędne ... chociaż prawdą jest również, że są przypadki, w których żadna implementacja nie przechowuje wartości długości. Zobacz moją odpowiedź. – Potatoswatter

0

Ale czym dokładnie jest długość tablicy? Czy jest to liczba bajtów w tablicy lub liczba elementów w tablicy?

Na przykład: w przypadku niektórych klasy A 100 rozmiar bajtów

A * myArray = Nowy A [100];

powinna długość (myArray) zwraca 100 lub 100 * 100? Ktoś może chcieć 100, ktoś może chcieć 10000.Tak więc nie ma żadnego prawdziwego argumentu.

+1

C++ konsekwentnie faworyzuje liczenie obiektów, nie bajtów. – Potatoswatter

1

Rozumiem, że filozofia C++ nie ma narzucać ludziom żadnej cechy, która ma potencjalny koszt, chyba że jest nieunikniona.

Może to wiązać się z dodatkowymi kosztami przechowywania tych informacji, a użytkownik może nie chcieć ponosić tych kosztów, jeśli nie potrzebują tych informacji. A ponieważ nie ma sensu przechowywać samej długości, jeśli chcesz, nie ma powodu, aby udostępniać funkcję językową, która ma koszt dla wszystkich korzystających z tablicy.

1

Dla odpowiednich tablic, czyli int a[length], masz już takiej usługi: wystarczy zrobić

#define length(A) (sizeof(A)/sizeof(*A)) 

i jesteś z nim zrobić.

Jeśli chodzi o uzyskanie długości tablicy wskazywanej przez wskaźnik, dobrze, wskaźniki i tablice są dwiema różnymi koncepcjami i łączenie ich nie ma sensu, nawet jeśli odpowiednie tablice "rozpadają się" na wskaźniki, gdy są potrzebne, a ty dostęp do tablic za pomocą arytmetyki wskaźnikowej.

Ale nawet jeśli nie weźmiemy to pod uwagę i mówić o aspektach technologicznych w C++ wykonawcze nie może wiedzieć, co długość tablicy jest, ponieważ new mogłaby polegać na malloc, która przechowuje długość tablicy w jego specyficzne sposoby, które są rozumiane tylko przez free: środowisko wykonawcze C++ przechowuje tylko dodatkowe informacje tylko wtedy, gdy masz niepuste destruktory. Niezły bałagan, co?

+0

Możesz również użyć std :: extent :: value. – bstamour

+0

dobrze wiedzieć, dzięki – akappa

0

typ C++, który działa podobnie jak większość „tablic” w językach, które obsługują length(array) jest std::vector<>, a robi mieć std::vector<>::size().

Wielkość zwykły [] tablic jest znany kompilator w zakresach gdzie rozmiar jest jawne, oczywiście, ale jest możliwe, aby przekazać je do zakresów, gdzie rozmiar jest nie znany kompilator. Daje to możliwość obsługi danych tablicowych niż języki, które muszą obsługiwać interogację (ponieważ muszą zapewnić, że rozmiar jest zawsze przekazywany).

Powiązane problemy