2015-01-04 13 views
20

Chcę uniemożliwić użytkownikowi mojej klasy z użyciem go jako zmienną automatyczną, więc piszę kod tak:Jaka jest różnica między "= domyślnym" destruktorem i pustym destruktorem?

class A { 
private: 
    ~A() = default; 
}; 

int main() { 
    A a; 
} 

Spodziewam się, że kod nie zostanie skompilowany, ale g ++ kompiluje bez błędów .

Jednak, kiedy zmienić kod do:

class A { 
private: 
    ~A(){} 
}; 

int main() { 
    A a; 
} 

Teraz, g ++ daje błąd że ~A() jest prywatny, jak jest moje oczekiwanie.

Jaka jest różnica między "= domyślnym" destruktorem a pustym destruktorem?

+4

Jaką wersję gcc? –

+1

Czytanie np. [to odwołanie do destruktora] (http://en.cppreference.com/w/cpp/language/destructor), różnica polega na tym, że dostarczony przez użytkownika destruktor (nawet jeśli jest pusty) jest * nietrywialny * i od reference: "Obiekty z trywialnymi destruktorami nie wymagają wyrażenia delete i można je usunąć, po prostu rozdzielając ich pamięć." –

+8

W twoim przypadku nie ma różnicy, zarówno [gcc4.9, jak i clang3.5 odmawiają kompilacji] (http://coliru.stacked-crooked.com/a/41976bc03bc12c79) Twój pierwszy przykład. To musi być błąd w twojej wersji gcc. – Praetorian

Odpowiedz

23

Twój pierwszy przykład nie powinien się kompilować. To reprezentuje błąd kompilatora, który kompiluje. Ten błąd jest naprawiony w gcc 4.9 i późniejszych.

Niszczarka zdefiniowana jako = default jest w tym przypadku banalna banalna. Można to wykryć za pomocą std::is_trivially_destructible<A>::value.

Aktualizacja

C++ 11 (i C++ 14) stwierdzają, że jeśli ktoś ma użytkownika oświadczył destruktor (a jeśli nie masz albo przenieść użytkownika oświadczył specjalny element) , niejawne generowanie konstruktora kopiowania i operatora przypisania kopiowania nadal ma miejsce, ale zachowanie to jest nieaktualne. Oznacza to, że jeśli na nim polegasz, kompilator może dać ostrzeżenie o wycofaniu (lub nie).

Zarówno:

~A() = default; 

oraz:

~A() {}; 

użytkownika oświadczył, a więc nie mają one znaczenia w odniesieniu do tej kwestii. Jeśli użyjesz któregoś z tych formularzy (i nie deklarujesz członków przeniesienia), powinieneś jawnie domyślić się, jawnie usunąć lub jawnie dostarczyć swoich członków kopii, aby uniknąć polegania na nieaktualnym działaniu.

Jeśli zadeklarujesz ruch elementów (z deklaratorem destruktora lub bez niego), członkowie kopiowania zostaną niejawnie usunięci.

+2

@delphifirst: Błędy kompilatora są bardzo popularne w dzisiejszych czasach. Kiedy byłem studentem, we wczesnych latach 80-tych, dowiedzieliśmy się, że pewne nieprawidłowe zachowanie było błędem w naszym kodzie, a nie w kompilatorze. Dzisiaj regularnie robię crash kompilatora (ICE, Internal Compiler Error), a potem nie ma wątpliwości, czyja to wina ... –

+0

@HowardHinnant: Tęsknię za dyskusją o niewykonaniu zobowiązania, a nie o zadeklarowaniu. Myślę, że byłoby to związane ze stosowaniem przez standard frazy "użytkownik zadeklarowany", np. w C++ 11 § 12,8/18. Proszę? –

+0

@ Cheersandhth.-Alf: Miło mi pomóc, ale nie rozumiem twojego pytania. Jeśli pytasz, czy element specjalny "= defaulted" jest zadeklarowany przez użytkownika, odpowiedź brzmi "tak", ale nie jest dostarczana przez użytkownika. –

Powiązane problemy