2015-04-20 15 views
24

Czy ta klasa:Czy klasa z usuniętym konstruktorem kopiowania może być trywialnie kopiowana?

class A { 
    public: 
    A() = default; 
    A(const A&) = delete; 
}; 

trywialnie copyable? (Przynajmniej dzyń wydaje się, że tak (live))

W szczególności będzie

A a,b; 
std::memcpy(&a, &b, sizeof(A)); 

powołać niezdefiniowanej zachowanie?

Kontekst: This answer [usunięty, ponieważ udowodniono błąd] oraz jego drzewo komentarzy.

+0

Dlaczego według Ciebie memcpy zachowałoby się inaczej, gdyby konstruktor kopiowania nie został usunięty? – iheanyi

+5

@iheanyi: Ponieważ istnieją reguły dotyczące tego, co można i czego nie można zrobić ze składowaniem, które wspiera obiekt. –

+0

@LightningRacisinObrit Nie, nie ma. Mogę z tym zrobić, co chcę. – iheanyi

Odpowiedz

24

Aktualizacja: Proponowana uchwała CWG 1734, obecnie w stanie "gotowy", by zmodyfikować [klasa]/P6 czytać:

trywialnie copyable klasa to klasa:

  • gdzie każdy konstruktor kopiowania, konstruktor ruchu, operator przypisania kopiowania i operator przeniesienia przypisania (12.8 [klasa.kopii], 13.5.3 [nadmiar]) jest albo usunięty, albo trywialny,
  • , który ma co najmniej jeden nieusunięty konstruktor kopiowania, konstruktor ruchu, operator przypisania kopiowania lub operator przeniesienia przeniesienia, i
  • który ma trywialny, nieusunięty destruktor (12.4 [class.dtor]).

Czyni zajęcia jak

struct B { 
    B() = default; 
    B(const B&) = delete; 
    B& operator=(const B&) = delete; 
}; 
nie dłuższy

trywialnie copyable. (Klasy tego rodzaju primow synchronizacja jak std::atomic<T> i std::mutex).

Jednakże A w PO znajduje się pośrednio zadeklarowane, nieusuniętych kopii zadanie operatora, który jest trywialne, tak że pozostaje trywialny copyable.

Oryginalna odpowiedź dla sytuacji sprzed CWG1734 została zachowana poniżej w celach informacyjnych.


Tak, nieco sprzeczne z intuicją, można to w uproszczalny sposób skopiować. [Klasa]/P6:

trywialny copyable klasą jest klasa:

  • ma nieoczywiste konstruktory kopiowania (12,8),
  • nie posiada nieoczywiste konstruktory przesuwania (12,8)
  • ma nieoczywiste operatorów przypisania kopiowania (13.5.3, 12.8),
  • nie posiada nieoczywiste operatorów przypisania przesuwania (13.5.3, 12.8), a
  • jest trywialny destructor (12.4).

[class.copy]/P12:

kopia/konstruktor ruch dla klasy X jest trywialny, gdy nie jest wprowadzona przez użytkownika, jego parametr typu lista- jest równoznaczne z parametrem typu liście z niejawny deklarację , a jeśli

  • klasa X ma wirtualny fu nctions (10.3) i brak zajęcia wirtualne zasad (10.1) i
  • klasy X ma nie-statycznych pól lotny wykwalifikowanej typu i
  • konstruktor wybrany skopiować/przenieść każdy podobiekt bezpośredniej klasy bazowej jest trywialne i
  • dla każdego niestatycznego elementu danych X, który jest typu klasy (lub ich tablicy), konstruktor wybrany do skopiowania/przeniesienia tego elementu jest prosty;

Podobnie ([class.copy]/p25)

kopia/ruch operatora przypisania do klasy X jest trywialny, gdy nie jest wprowadzona przez użytkownika, jego parametr typu -list jest równoznaczne z parametrem typu liście z niejawny deklarację , a jeśli

  • klasie X nie ma funkcji wirtualnych (10.3) i żadnych wirtualnych klas bazowych (10.1) i
  • klasa X nie ma niestatycznych elementów danych o typie z lotnością, a
  • jest operatorem przypisania wybranym do kopiowania/przenoszenia każdego bezpośredniego podobiekt klasy podstawowej jest trywialny, a dla każdego niestatycznego elementu danych X, który jest typu klasy (lub ich tablicy), operator przypisania wybrany do kopiowania/przenoszenia tego elementu jest prosty;

[class.dtor]/P5

Destruktor jest trywialny, gdy nie jest wprowadzona przez użytkownika i w przypadku gdy:

  • destruktory nie virtual,
  • wszystkie bezpośrednie klasy bazowe w swojej klasie mają trywialne destruktory i
  • dla wszystkich niestatycznych elementy danych swojej klasy, które są typu klasy (lub ich tablica), każda taka klasa ma trywialny destruktor .

[dcl.fct.def.default]/P5:

Funkcja jest użytkownika warunkiem jeśli jest łatwy i nie zadeklarował jednoznacznie niewykonaniem lub usunięte na pierwszym zgłoszeniu.

Rzeczywiście, to było a source of problems for the committee itself, ponieważ w obecnej definicji atomic<T> (wraz z muteksy i zmiennych warunek) byłoby trywialnie copyable. (I oczywiście pozwolenie komuś na memcpy przez atomic lub mutex bez wywoływania UB byłoby ... powiedzmy poważnie problematyczne.) Zobacz także N4460.

+0

Heh, już pokryłeś więcej niż ja, zanim odpowiedziałem. Niezłe znalezisko, które może oznaczać, że nawet jeśli obecnie można go skopiować, może nie zostać łatwo skopiowana. – hvd

+0

@hvd Obecne proponowane rozwiązanie tego problemu LWG jest w zasadzie magicznym zaklęciem ("nie ważne co mówi rdzeń, to nie jest trywialnie kopiowalne !!!"). W mailingu pre-Lenexa znajduje się artykuł omawiający różne możliwe sposoby rozwiązania tego problemu. –

+0

Wygląda na to, że poprawna poprawka brzmi: "MA to trywialny konstruktor kopiowania lub trywialny konstruktor ruchu, który nie jest usuwany ORAZ Ma trywialnego operatora przypisania lub przeniesienia, który nie został usunięty". Jeśli istnieje ważna kopia, która również jest banalna, wówczas banalna kopia jest ważna. Nie ma żadnej różnicy, że może istnieć również bardziej wyszukany egzemplarz. –

Powiązane problemy