2012-10-31 26 views
14

Mam dwa bloki kodu o new[] i delete[]:Po p = nowy ciąg [0] i p = nowy int [0], dlaczego wersja łańcucha ulega awarii podczas usuwania [] p?

1)

#include <string> 

int main() 
{ 
    std::string *p = new std::string[0]; 
    delete[] p; 

    return 0; 
} 

2), w tym przypadku, ja po prostu zmienić std::string do int

int main() 
{ 
    int *p = new int[0]; 

    delete[] p; 

    return 0; 
} 

Moje pytanie brzmi:

Dlaczego pierwszy program ulega awarii z następującym komunikatem (w środowisku Linux):

Segmentation fault (core dumped) 

Ale drugi program działa dobrze bez żadnego błędu?

EDIT

kompilator: g++ (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2

wystarczy użyć g++ bez żadnego argumentu, aby go skompilować.

Jeśli jest to błąd kompilatora, czy wystąpi awaria czy nie, zgodnie ze standardem?

+2

Wygląda jak błąd kompilatora – Andrey

+1

To nie psuje tutaj. Który kompilator używasz (z dokładną wersją) i jak go kompilujesz? – amaurea

+1

Awaria za pomocą g ++ (4.7 i 4.8), nie ulega awarii z powodu klang. Zgaduję, że jest to błąd w g ++. – kennytm

Odpowiedz

13

To powinien być błąd w gcc. To całe wyrażenie new[] jest ignorowane, a p staje się niezainicjowane, a następnie delete[] niezainicjowany wskaźnik, który ulega awarii. Gdybyśmy skompilować program z -Wall będzie cię ostrzec, że

ostrzeżenie: „p” jest używane w tej funkcji uninitialized

który jest wyraźnie źle. Wyrażenie new X[0] jest dobrze zdefiniowane zarówno w C++ 03, jak i C++ 11 (§5.3.4/7) i działa poprawnie w klangu, więc jedynym logicznym wnioskiem jest to, że jest to błąd gcc.


Wyeliminowanie błędów-of new[] istnieje tylko wtedy, gdy typ ma być wykonana każdą nietrywialne konstruktora. A w przypadku segfault ten typ ma destruktor, ponieważ wtedy delete[] będzie musiał usunąć zaznaczenie niezainicjowanego wskaźnika. W związku z tym ulega awarii dla std::string, ale nie int, ponieważ int jest trywialne i std::string nie jest.


Można to obejść za pomocą zmiennej pośredniej, tak że ekspresja nie można ocenić na 0 bezpośrednio:

size_t length = 0; 
std::string* p = new std::string[length]; 
// ... 
delete[] p; 
+0

Jestem zaskoczony, że hack działa ... Na liveworkspace mam 3 zachowania: oryginalny kod OP (ostrzeżenie + awaria), to obejście (bez ostrzeżenia, bez awarii), użycie 'size_t const length = 0;' (warning, bez wypadku). I * love * gcc ... –