Prosta aplikacja testowa:
cout << new int[0] << endl;
wyjścia:
0x876c0b8
Wygląda na to, że działa. Co standard mówi o tym? Czy zawsze „przydzielanie” pustego bloku pamięci jest legalne?
Prosta aplikacja testowa:
cout << new int[0] << endl;
wyjścia:
0x876c0b8
Wygląda na to, że działa. Co standard mówi o tym? Czy zawsze „przydzielanie” pustego bloku pamięci jest legalne?
Odpowiedzi:
Od 5.3.4 / 7
Od 3.7.3.1/2
Również
Oznacza to, że możesz to zrobić, ale nie możesz legalnie (w dobrze zdefiniowany sposób na wszystkich platformach) wyłuskać dostępnej pamięci - możesz tylko przekazać ją do skasowania tablicy - i powinieneś ją usunąć.
Oto interesująca notatka (tj. Nie normatywna część normy, ale dołączona do celów ekspozycyjnych) dołączona do zdania z 3.7.3.1/2
źródło
new[]
zdelete[]
- niezależnie od wielkości. W szczególności, gdy dzwonisznew[i]
, potrzebujesz nieco więcej pamięci niż ta, którą próbujesz przydzielić, aby przechowywać rozmiar tablicy (która jest później używanadelete[]
podczasTak, legalne jest przydzielanie tablicy o zerowej wielkości w ten sposób. Ale musisz go również usunąć.
źródło
int ar[0];
jest to nielegalne, dlaczego nowy jest OK?sizeof (type)
oczekuje się, że nigdy nie zwróci zera. Patrz na przykład: stackoverflow.com/questions/2632021/can-sizeof-return-0-zeroKażdy obiekt ma unikalną tożsamość, tj. Unikalny adres, co oznacza niezerową długość (rzeczywista ilość pamięci zostanie cicho zwiększona, jeśli poprosisz o zero bajtów).
Jeśli przydzielono więcej niż jeden z tych obiektów, okazałoby się, że mają one różne adresy.
źródło
operator []
przechowuje również gdzieś rozmiar tablicy (patrz isocpp.org/wiki/faq/freestore-mgmt#num-elems-in-new-array ). Więc jeśli implementacja przydzieli liczbę bajtów z danymi, może po prostu przydzielić dla liczby bajtów i 0 bajtów dla danych, zwracając wskaźnik 1-ostatni-ostatni.operator new[]
powinny zwracać różne wskaźniki. BTW,new expression
ma kilka dodatkowych zasad (5.3.4). Nie mogłem znaleźć żadnej wskazówki, któranew
przy rozmiarze 0 jest faktycznie wymagana do przydzielenia czegokolwiek. Przepraszam, przegłosowałem, ponieważ uważam, że twoja odpowiedź nie odpowiada na pytania, ale zawiera pewne kontrowersyjne stwierdzenia.new[]
implementacja zwracała adresy w zakresie, w którym nie ma dynamicznej pamięci mapowanej, a więc tak naprawdę nie używa żadnej pamięci (podczas korzystania z przestrzeni adresowej)while(!exitRequested) { char *p = new char[0]; delete [] p; }
pętlę bez wskaźników ponownego przetwarzania zapadłby się w pył, zanim mógł zabraknąć przestrzeni adresowej, ale na platformie z 32-bitowymi wskaźnikami byłby to znacznie mniej uzasadnione założenie.Tak, jest całkowicie legalne, aby przydzielić
0
rozmiar blokunew
. Po prostu nie możesz zrobić nic przydatnego, ponieważ nie ma ważnych danych, do których miałbyś dostęp.int[0] = 5;
jest nielegalne.Uważam jednak, że standard pozwala na rzeczy takie jak
malloc(0)
zwrotNULL
.Nadal będziesz potrzebował
delete []
wskaźnika, który otrzymasz z przydziału.źródło
Znalazłem Effective C ++ Third Edition w następujący sposób: „Punkt 51: Przestrzegaj konwencji podczas pisania nowego i usuwania”.
źródło
Gwarantuję ci, że nowy int [0] kosztuje dodatkowe miejsce, odkąd go przetestowałem.
Na przykład użycie pamięci przez
jest znacznie mniejszy niż
Wykorzystanie pamięci drugiego fragmentu kodu minus zużycie pierwszego fragmentu kodu to pamięć używana przez liczne nowe int [0].
źródło