2016-01-03 29 views
10

Próbuję zrozumieć, jak związki zostały rozszerzone przez C++ 11. Jedną z rzeczy, która się zmieniła, jest możliwość korzystania teraz z niestatycznych elementów danych z nietrywialnymi specjalnymi funkcjami członków. Od cppreference.comZwiązki w C++ 11: domyślny konstruktor wydaje się być usunięty

Jeśli związek zawiera non-statycznego elementu danych z niebanalną specjalnej funkcji składowej (domyślnego konstruktora, kopiowanie/konstruktora przenosić, kopiować/cesja ruchu, lub destructor), że funkcja zostanie usunięta domyślnie w związku i musi zostać jednoznacznie określone przez programistę. Co najwyżej jeden element danych może mieć domyślny inicjator członu.

próbuję następujący kod:

struct X 
{ 
    ~X() {}; 
}; 

union U 
{ 
    X x; 
    ~U() {}; 
}; 

int main() 
{ 
    U s1{}; // works, probably aggregate initialization 
    U s2; // DOES NOT compile, why? 
} 

Live on Coliru

Tutaj X (który służy jako członek danych unii) ma pod warunkiem użytkownika destruktora, stąd destruktora unia jest domyślnie usunięta. W związku z tym zapewniam jedno wyraźnie. Jednak kod nie skompilować, z błędem

notatka: „U :: U()” jest domyślnie usunięte, ponieważ definicja domyślny byłoby źle sformułowane:

Kod kompiluje jeśli Usuwam ostatnią linię U s2;.

Pytanie Co się tutaj dzieje? Dlaczego kompiluje się U s1{};, ale U s2; nie? Czy domyślny ctor związku jest oznaczony jako usunięty (jeśli tak, to dlaczego ?!), a w pierwszym przypadku mamy właśnie inicjację agregującą? Zauważ, że jeśli dostarczę U(){}; // not U() = default;, kod się skompiluje (ale nie, jeśli dostarczę tylko ctorowi z X).

EDIT

Po wykopaniu w normie (N4527)

Związków: 9,5/2 [class.union]

[Uwaga: Jeśli którykolwiek niestatyczny element danych unii ma nietrywialny domyślny konstruktor (12.1), konstruktor kopiowania (12.8), konstruktor ruchu (12.8), operator przypisania kopiowania (12.8), operator przeniesienia przypisania (12.8) lub destruktor (12.4), odpowiedni członek func Unia musi być dostarczona przez użytkownika lub zostanie domyślnie usunięta (8.4.3) dla związku. -endnote]

wydaje się, że jest to błąd gcc (teraz zgłoszony here). Kod kompiluje się na clangu i gcc 4.8.2 lub wcześniejszym, łamie się na gcc4.9 i później (dzięki @ T.C. Za wskazanie). Kompilator: g ++ 5.3, -std=c++11 używany.

+1

[Clang] (http://coliru.stacked-crooked.com/a/b58a360400009fa9) jest całkowicie zadowolony z tego kodu. To właściwie wygląda na błąd GCC. –

+0

@ T.C. Tak, faktycznie widziałem to teraz po twoim komentarzu. Po raz pierwszy miałem wrażenie, że klang odrzucił go, mógł zostać przetestowany w zmodyfikowanej wersji. Zmieniono ostatnią linijkę pytania, dzięki. – vsoftco

+0

@ T.C. Spróbuję zagłębić się w standard ... – vsoftco

Odpowiedz

2

Cytat cppreference jest niejasny. Dzieje się tak, że jeśli członek związku zdefiniuje ANY tych nietrywialnych funkcji specjalnego elementu, to domyślnie zostaną one usunięte w zespole.

Ponieważ masz nietrywialny destruktor dla X, domyślny konstruktor U jest usuwany.

+0

Dzięki, jeśli tak, to ma to sens. A 'U s1 {};' działa, ponieważ używamy inicjalizacji agregacji, prawda? – vsoftco

+0

Głównie, tak. Reguły C++ 11 umożliwiają tworzenie bardziej złożonych typów w związkach, ale musisz zarządzać wywoływanie ich konstruktorów i destruktorów ręcznie w oparciu o znacznik dowolnego typu, którego używasz w obiekcie/funkcji zarządzającej związkiem. Zwykle oznacza to użycie nowego miejsca docelowego/usunięcia. –

+0

Masz ofertę? Nie sądzę, że tak mówi standard. –

1

X nie jest typem strąk, ponieważ nie jest trywialnie copiable, ponieważ ma destruktor Również U nie jest typu pod.

U s2; spróbować zadzwonić domyślny Costructor że zostanie usunięty więc błędu

U s1 {}; użycie członkiem mądry inicjalizacji i nie wywołać dowolną Costructor

W jedności z braku członka pod domyślnym Costructor unii jest usuwany, ponieważ wywołałby domyślną strukturę kosztów członków, tj. kompilator nie wie, który członek wywoła domyślny kosztorysowy

Union XX{ 
    string m1; 
    vector <int> m2; 
} 

domyślny costructor z XX nie może wywołać domyślnego costructor m1 ORAZ m2, więc jest usuwany

+1

Zgadzam się ze stwierdzeniem, ale nie rozumiem, dlaczego domyślny konstruktor został usunięty. – vsoftco

+0

@vsoftco Dodaję pewne wyjaśnienie tego, co myślę, że się pojawi – alangab

+0

Może tak być, chociaż nie widzę powodu, dla którego kompilator nie mógłby po prostu wywołać konstruktora pierwszego elementu. Tak samo, jak w przypadku 'XX x {" test "};', kompilator wywołuje ctor 'm1', tj. Ctor pierwszego elementu. – vsoftco