2013-08-14 7 views
8

użyciu C++ 11, proszę utworzyć tablicę logicznych i natychmiast oczywiste, żeCzy mogę określić rozmiar tablicy utworzonej za pomocą "nowego typu [n]" w C++?

bool *mymap = new bool[n]; 

n jest zmienna.

Czy to już wyczyściło pamięć zajmowaną przez macierz? Jeśli nie, czy istnieje lepsze podejście do czyszczenia tablicy niż użycie pętli ponad wszystkimi elementami, ustawiając każdy z nich na fałsz indywidualnie?

Rozważałem użycie std: memset(), ale to wymaga ode mnie poznania rozmiaru tablicy. Teraz początkujący mogą powiedzieć: Łatwe, rozmiar to n * sizeof (bool). Ale ja tego nie kupuję. Kompilator może zdecydować się na spakowanie ich inaczej, nawet pakować je jako bity, prawda?

Czy istnieje sposób na lepsze określenie rozmiaru tablicy? Wyobrażam sobie, że może istnieć funkcja std: arraysize(), która po prostu zwraca przestrzeń przydzielonej tablicy w pamięci. W końcu te informacje muszą być w jakiś sposób zachowane w środowisku wykonawczym, albo wywołanie usunięcia nie wie, ile zwolnić, prawda?

+7

Co z 'std :: vector'? – chris

+0

@chris std :: wektor jest przesadny w moim konkretnym przypadku użycia - używanie bezpośredniej tablicy jest także szybsze. –

+9

Jeśli utworzysz 'std :: vector' o określonym rozmiarze, narzut jest minimalny. Powinieneś naprawdę to sprawdzić. –

Odpowiedz

10

Odpowiedź na konkretne pytanie brzmi: nie, nie można określić długości tablicy wskazanej przez mymap. Język nie zapewnia po prostu żadnego mechanizmu.

Ale jeśli wszystko, co chcesz zrobić, to upewnić się, że wszystkie elementy tablicy są ustawione na false, to wszystko co musisz zrobić, to wartość zainicjować go:

bool* mymap = new bool[n](); 
//      ^^ 

Niestety, ten działa tylko dla wartości zerowe dla typów wbudowanych. Nie byłoby równoważnego sposobu ustawienia wszystkich wartości na true.

+2

Lub możesz użyć jednolitej inicjalizacji: 'new bool [n] {}', 'new bool [n] {true, false, true}', etc – bames53

4

Nie, nie możesz, ponieważ w rzeczywistości nie jest to tablica. mymap jest zwykłym wskaźnikiem do pamięci sterty, a jeśli potrzebujesz znać rozmiar, musisz to zrobić samodzielnie lub użyć standardowego pojemnika, takiego jak std::vector.

Aha, a jeśli chcesz bardziej ogólny wariant memset przeczytaj o std::fill.

+0

Zdajesz sobie sprawę, że funkcja malloc zna rozmiar bloku alloc'd, prawda? Dlaczego więc nowy operator nie powinien tego zrobić? –

+0

@ThomasTempelmann 'malloc' i' new' nie muszą znać rozmiaru przydzielonego bloku - na przykład, mogą zaokrąglić rozmiar do następnej dostępnej mocy dwóch (lub do rozmiaru następnego dostępnego bloku równego lub większy rozmiar) i przechowuj to. Tylko 'nowe T [n]' gdzie 'T' jest typem bez POD jest wymagane do przechowywania dokładnego' n'. – user4815162342

+0

@ThomasTempelmann * System operacyjny * może śledzić rozmiar, ale kompilator z całą pewnością nie. Po prostu prosi system operacyjny o kawałek pamięci, a następnie zapomina o rozmiarze. –

4

Nie, kompilator nie może zdecydować się pakować je chyba tak, że wielkość regionu jest n * sizeof(bool) - robi to w inny sposób złamie zdolność do rozwiązywania poszczególnych członków tablicy jako mymap[x] (który jest taki sam jak *(mymap + x)) .

W tym przypadku sugestia dla początkujących jest prawidłowa.

6

Nie można tego zrobić w standardowy sposób. Jednak różne kompilatory obsługują różne hacki, na przykład:

#if defined(_MSC_VER) || (defined(__GNUC__) && defined(_WIN32)) 
     // a dirty MSVC and MinGW hack 
     size_t Size = _msize(mymap); 
#elif defined(__GNUC__) 
     // a dirty glibc hack 
     size_t Size = malloc_usable_size(mymap); 
#else 
    #error Implement for any other compiler 
#endif  

Ale to są prawdziwe hacki, więc uważaj.

Przy okazji, std::vector może pomóc rozwiązać problem w ramach standardu.

2

Można spróbować to:

bool *mymap = new bool[n](); 

Jednak ten ustawia się false i nie można używać taki sposób, aby ustawić true.

2

Załóżmy, że kompilator decyduje się na inne opakowanie.

Założenie 1: kompilator pakuje kilka bitów razem w jeden bajt. Jeśli weźmiesz adres pojedynczego elementu wewnątrz tablicy, będzie to typ bool. Ponieważ kompilator nie może (ogólnie) odliczyć tego, co zrobisz z tym adresem (np. Przekazując go do funkcji, która przekazuje je do biblioteki, ...), pakowanie bitów w jeden bajt nie może się zdarzyć. W przeciwnym razie kompilator musi zamaskować odpowiedni bit z jego spakowanego regionu i przenieść go gdzieś jako prawdziwy bool.

Założenie 2: kompilator używa więcej niż sizeof (bool) dla jednej wartości bool. Bardzo mało prawdopodobne - ponieważ wtedy sizeof (bool) byłby po prostu większy. Pointer-manipulacje są nadal możliwe, a w przypadku tablic bitowych należy wprowadzić inną magiczną logikę.

Założenie 3: kompilator używa różnych rozmiarów dla różnych pól tablicy - jeszcze bardziej nieprawdopodobne. Wymagane informacje administracyjne są po prostu zbyt duże.

Z tych 3 myśli powiedziałbym, że proste rozwiązanie jest najlepsze. Dla pewności teraz i dla całej przyszłości twojego programu napisz mały test jednostkowy, który dokładnie to przetestuje (np. Uzyskaj adres pierwszej wartości, rzuć go na wskaźnik typu, który ma taki sam rozmiar jak bool, obliczyć adres elementu n, odrzucić ten adres z powrotem do wskaźnika bool, napisać coś tam i porównać z dostępem do tablicy). Wtedy dostaniesz powiadomienie, jeśli coś się zmieni - ale wątpię, by tak się stało.


Sidenote - oczywiście kompilator zawsze może przydzielić więcej pamięci niż jest to wymagane. Mimo to, tablica ma taki rozmiar (jest po prostu umieszczona w większej części pamięci).

+0

Moja myśl jest następująca: Gdy bool może zajmować 1 bajt, tablica może używać granic wyrazów dla każdego elementu, aby zoptymalizować wydajność dostępu do pamięci. Ale wtedy * a jest takie samo jak [0], a ++ a musi przejść do następnego elementu tablicy. Przy tym prawdopodobnie kompilator nie może spakować tablicy elems z żadnym rozmiarem innym niż sizeof (elem). –

+0

jeśli używa granic wyrazów, aby zoptymalizować wydajność dostępu, zrobiłby to samo dla pojedynczych wartości (wyobrazić sobie na przykład w structs). Oznacza to, że sizeof (bool) będzie wynosił 2, a założenie n * sizeof (bool) == rozmiar tablicy będzie wynosić –

2

W gołej kości C++, nie jest to niemożliwe. Jednak zachęcamy (i naprawdę powinieneś) rozważyć użycie klasy do zarządzania pamięcią.

w C++ 98, można użyć boost::scoped_array lub grupę std::vector (choć dla bool może wolisz std::vector<char>).

W C++ 11, należy rozważyć zastąpienie boost::scoped_array przez std::unique_ptr<bool[]>.

Problem do tej pory, z wyjątkiem std::vector, żaden z nich nie zna rozmiaru tablicy, którą zawierają; po prostu zajmują się pamięcią.

W C++ 14 pojawia się nowy kandydat: std::dynarray. Jest to przycięta wersja std::vector, której rozmiaru nie można zmienić dynamicznie. Krótko mówiąc, dokładnie to, czego potrzebujesz: tylko tablica i jej długość, bez żadnych kosztów ogólnych.

Jeśli Twój ulubiony kompilator/toolchain nie obsługuje dynarray jeszcze można łatwo wdrożyć go samodzielnie:

template <typename T> 
class dynarray { 
public: 
    // methods go here. 
private: 
    size_t size; 
    std::unique_ptr<T[]> array; 
}; // class dyn_array 
+0

Dzięki za wskaźnik do std: dynarray. 2014 nie jest już tak daleko :) –

Powiązane problemy