Dopiero zaczynam poznawać C ++ i chcę poznać kilka dobrych nawyków. Jeśli właśnie przydzieliłem tablicę typu int
z new
operatorem, jak mogę zainicjować je wszystkie na 0 bez samodzielnego przeglądania ich wszystkich w pętli? Powinienem po prostu użyć memset
? Czy jest na to sposób „C ++”?
c++
initialization
memory-management
new-operator
dreamlax
źródło
źródło
&vector[0]
.Odpowiedzi:
Jest to zaskakująco mało znana funkcja C ++ (o czym świadczy fakt, że nikt jeszcze tego nie podał jako odpowiedzi), ale w rzeczywistości ma specjalną składnię do inicjowania wartości w tablicy:
Zauważ, że musisz użyć pustych nawiasów - nie możesz na przykład użyć
(0)
ani niczego innego (dlatego jest to przydatne tylko do inicjalizacji wartości).Jest to wyraźnie dozwolone w ISO C ++ 03 5.3.4 [wyr.new] / 15, który mówi:
i nie ogranicza typów, dla których jest to dozwolone, podczas gdy
(expression-list)
formularz jest wyraźnie ograniczony przez dalsze reguły w tej samej sekcji, tak że nie zezwala na typy tablicowe.źródło
new int[10] {}
. Możesz również podać wartości do zainicjowania:new int[10] {1,2,3}
Zakładając, że naprawdę chcesz mieć tablicę, a nie std :: vector, „sposób C ++” wyglądałby tak
Ale pamiętaj, że pod maską nadal jest to po prostu pętla, która przypisuje każdemu elementowi wartość 0 (naprawdę nie ma innego sposobu, aby to zrobić, z wyjątkiem specjalnej architektury z obsługą na poziomie sprzętu).
źródło
Istnieje wiele metod przydzielania tablicy typu wewnętrznego i wszystkie z nich są poprawne, chociaż to, która z nich wybrać, zależy ...
Ręczna inicjalizacja wszystkich elementów w pętli
Korzystanie
std::memset
z funkcji z<cstring>
Korzystanie
std::fill_n
z algorytmu z<algorithm>
Korzystanie z
std::vector
konteneraJeśli dostępny jest C ++ 0x , użyj funkcji listy inicjalizacyjnej
źródło
int array[SIZE] ={1,2,3,4,5,6,7};
notacji, mógłbym użyćvoid rotateArray(int (& input)[SIZE], unsigned int k);
deklaracji funkcji, co by było, gdybyśmy użyli pierwszej konwencji? jakieś sugestie?std::memset
jest błędny - przechodzisz 10, wydaje się, że oczekuje się liczby bajtów - patrz en.cppreference.com/w/cpp/string/byte/memset . (Myślę, że to ładnie pokazuje, dlaczego należy unikać takich niskopoziomowych konstrukcji, jeśli to możliwe.)Jeśli alokowana pamięć jest klasą z konstruktorem, który robi coś pożytecznego, operator new wywoła ten konstruktor i pozostawi zainicjowany obiekt.
Ale jeśli przydzielasz POD lub coś, co nie ma konstruktora, który inicjuje stan obiektu, nie możesz przydzielić pamięci i zainicjować tej pamięci operatorem new w jednej operacji. Masz jednak kilka opcji:
1) Zamiast tego użyj zmiennej stosu. Możesz alokować i inicjalizować domyślne w jednym kroku, na przykład:
2) użycie
memset()
. Zwróć uwagę, że jeśli przydzielany obiekt nie jest POD , ustawienie go jest złym pomysłem. Jednym konkretnym przykładem jest to, że jeśli ustawisz klasę, która ma funkcje wirtualne, rozwalisz vtable i pozostawisz obiekt w stanie bezużytecznym.3) Wiele systemów operacyjnych ma wywołania, które robią to, co chcesz - alokują na stercie i inicjalizują dane w czymś. Przykładem systemu Windows byłoby
VirtualAlloc()
4) Zazwyczaj jest to najlepsza opcja. Unikaj konieczności samodzielnego zarządzania pamięcią. Możesz użyć kontenerów STL, aby zrobić wszystko, co zrobiłbyś z pamięcią surową, w tym alokować i inicjować wszystko za jednym zamachem:
źródło
Tak jest:
Użyj wektora zamiast dynamicznie przydzielanej tablicy. Korzyści obejmują brak konieczności zawracania sobie głowy jawnym usuwaniem tablicy (jest ona usuwana, gdy wektor wychodzi poza zakres), a także to, że pamięć jest automatycznie usuwana, nawet jeśli zostanie zgłoszony wyjątek.
Edycja: Aby uniknąć dalszych negatywnych głosów ze strony osób, które nie zawracają sobie głowy czytaniem poniższych komentarzy, powinienem wyjaśnić, że ta odpowiedź nie mówi, że wektor jest zawsze właściwą odpowiedzią. Ale z pewnością jest to bardziej C ++ sposób niż „ręczne” upewnienie się, że usunięto tablicę.
Teraz w C ++ 11 istnieje również std :: array, która modeluje tablicę o stałym rozmiarze (w porównaniu do wektora, który może rosnąć). Istnieje również std :: unique_ptr, który zarządza dynamicznie alokowaną tablicą (która może być połączona z inicjalizacją, zgodnie z odpowiedzią w innych odpowiedziach na to pytanie). Każdy z nich jest bardziej C ++ sposobem niż ręczna obsługa wskaźnika do tablicy, IMHO.
źródło
std::vector
zamiast dynamicznie przydzielanych tablic? Jakie są zalety używania tablicy zamiast wektora i odwrotnie?std::vector
.vector
wszędzie, niezależnie od kontekstu, nazywa się „pisaniem kodu Java w C ++”.std::fill
jest w jedną stronę. Pobiera dwa iteratory i wartość do wypełnienia regionu. To, lub pętla for, byłoby (jak przypuszczam) bardziej C ++ sposobem.Ustawienie tablicy pierwotnych typów całkowitych na 0
memset
jest w porządku, chociaż może unieść brwi. Weź również pod uwagęcalloc
, chociaż jest to trochę niewygodne w użyciu z C ++ ze względu na rzutowanie.Ze swojej strony prawie zawsze używam pętli.
(Nie lubię zastanawiać się nad intencjami ludzi, ale to prawda, że
std::vector
wszystkie rzeczy są równe, lepiej niż ich używaćnew[]
).źródło
zawsze możesz użyć memset:
źródło
memset
, ale nie byłem pewien, czy to jest sposób C ++ na podejście do problemu.10 * sizeof( *myArray )
jest bardziej udokumentowany i odporny na zmiany niż10 * sizeof( int )
.Zwykle w przypadku dynamicznych list elementów używasz rozszerzenia
std::vector
.Generalnie używam memset lub pętli do dynamicznej alokacji pamięci surowej, w zależności od tego, jak zmienna przewiduję ten obszar kodu w przyszłości.
źródło