C++11 Defaulted & Deleted Functions / 48 C++11 Defaulted & Deleted Functions Detlef Wilkening .
-
Upload
morency-bornhoft -
Category
Documents
-
view
124 -
download
1
Transcript of C++11 Defaulted & Deleted Functions / 48 C++11 Defaulted & Deleted Functions Detlef Wilkening .
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 1 / 48
C++11Defaulted & Deleted Functions
Detlef Wilkeninghttp://www.wilkening-online.de8.5.2014 & 14.8.2014
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 2 / 48
Themen: 6 spezielle Funktionen in Klassen und ihre Erzeugungs-Regeln Explicitly Defaulted Functions Deleted Functions ISO & Links
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 3 / 48
6 spezielle Member-Funktionen
in Klassen und ihre Erzeugungs-Regeln
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 4 / 48
Spezielle Member-Funktionen einer Klasse "A"• Standard-Konstruktor A()• Destruktor ~A()• Kopier-Konstruktor A(const A&)• Kopier-Zuweisungs-Operator A& operator=(const A&)• Move-Konstruktor A(A&&)• Move-Zuweisungs-Operator A& operator=(A&&)
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 5 / 48
Standard-Konstruktor: A()• Der implizite Standard-Konstruktor wird nur dann erzeugt,
wenn kein anderer Konstruktor explizit deklariert wurde, undwenn er erzeugbar ist
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 6 / 48
Destruktor: ~A()• Der implizite Destruktor wird immer erzeugt,
außer es gibt einen user-deklarierten Destruktor, oder er ist nicht erzeugbar.
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 7 / 48
Kopier-Konstruktor: A(const A&)• Der implizite Kopier-Konstruktor wird erzeugt, wenn:
• er nicht explizit deklariert wurde,• er generierbar ist, d.h. alle Elemente der Klasse kopierbar sind,• es keinen expliziten Move-Konstruktor gibt (C++11), und• es keinen expliziten Move-Zuweisungs-Operator gibt (C++11)
• Zusätzlich in C++11:• Wenn der Destruktor oder der Kopier-Zuweisungs-Operator explizit deklariert
wurde, dann ist die Erzeugung des Kopier-Konstruktors deprecated.
Kopier-Zuweisungs-Operator: A& operator=(const A&)• Der implizite Kopier-Zuweisungs-Operator wird erzeugt, wenn:
• er nicht explizit deklariert wurde,• er generierbar ist, d.h. alle Elemente der Klasse kopier-zuweisbar sind,• es keinen expliziten Move-Konstruktor gibt (C++11), und• es keinen expliziten Move-Zuweisungs-Operator gibt (C++11)
• Zusätzlich in C++11:• Wenn der Destruktor oder der Kopier-Konstruktor explizit deklariert wurde,
dann ist die Erzeugung des Kopier-Zuweisungs-Operators deprecated.
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 8 / 48
Move-Konstruktor: A(A&&)• Der implizite Move-Konstruktor wird erzeugt, wenn:
• er nicht explizit deklariert wurde,• kein expliziter Kopier-Konstruktor deklariert wurde,• kein expliziter Kopier-Zuweisungs-Operator deklariert wurde,• kein expliziter Move-Zuweisungs-Operator deklariert wurde,• kein expliziter Destruktor deklariert wurde, und• er generierbar ist
D.h. wenn alle Elemente der Klasse "movebar" sind
Move-Zuweisungs-Operator: A& operator=(A&&)• Der implizite Move-Zuweisungs-Operator wird erzeugt, wenn:
• er nicht explizit deklariert wurde,• kein expliziter Kopier-Konstruktor deklariert wurde,• kein expliziter Kopier-Zuweisungs-Operator deklariert wurde,• kein expliziter Move-Konstruktor deklariert wurde,• kein expliziter Destruktor deklariert wurde, und• er generierbar ist
D.h. wenn alle Elemente der Klasse "move-zuweisbar" sind
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 9 / 48
C++ 11 erlaubt eine exakte Steuerung der Generierung dieser6 speziellen Member-Funktionen• Dafür gibt es in C++11 nun die Möglichkeit mit "=default" oder "=delete" die
Generierung zu aktivieren oder zu verbieten• Siehe ISO/IEC 14882, Kapitel 12.1, 12.4, 12.7, 12.8 und 13.5.3
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 10 / 48
Explicitly Defaulted Functions
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 11 / 48
Explicitly-defaulted Functions• So nennt der Standard sie: ISO/IEC 14882:2011(E) § 8.4.2• Bezieht sich nur auf die speziellen Member-Funktionen
• Nur: Standard-Konstruktor A() Destruktor ~A() Kopier-Konstruktor A(const A&) Kopier-Zuweisungs-Operator A& operator=(const A&) Move-Konstruktor A(A&&) Move-Zuweisungs-Operator A& operator=(A&&)
• Denn diese könnten nicht erzeugt werdenBzw. werden speziell benötigt (z.B. virtueller Destruktor)
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 12 / 48
Wird eine der speziellen Member-Funktionen nicht erzeugt, so kann man die Erzeugung erzwingen• = default hinter die Funktions-Deklaration
class A
{
public: A() = default; ~A() = default; A(const A&) = default; A& operator=(const A&) = default; A(A&&) = default; A& operator=(A&&) = default;
};
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 13 / 48
Haupt-Anwendung:• Erzeugungs-Regeln verhindern die automatische Erzeugung• Funktion soll trotzdem vorhanden sein• Achtung
• Auch "explizit defaulted Funktionen" sind user-deklarierte Funktionenund greifen daher in die Erzeugungs-Regeln ein
class A
{
public: A() = default; // Soll normal da sein A(int); // Verhindert Erzeugung vom Standard-Konstruktor
private: std::string s;
};
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 14 / 48
Weitere Anwendungen• Veränderung des Zugriffs-Bereichs• Virtueller Destruktor• Trivialer Typ
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 15 / 48
Veränderung des Zugriffs-Bereichs• Beispiel
• Standard-Konstruktor wäre vorhanden• Aber public – soll protected sein• Möglich mit = default
class A
{
public:
virtual ~A();
protected: A() = default; // Soll normal da sein, aber protected
private: std::string s;
};
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 16 / 48
Virtueller Destruktor• Basis-Klassen sollten einen virtuellen Destruktor haben• Mußte früher häufig explizit leer implementiert werden• Heute einfach mit = default
class A
{
public:
virtual ~A() = default; // Normal vorhanden, aber virtual
};
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 17 / 48
Trivialer Typ• Eine Klasse mit z.B. einem expliziten Standard-Konstruktor ist nicht trivial
• Kein POD – „Plain Old Data“• =>
• Compiler kann nicht beliebig optimieren• Funktionen dürfen nicht übersprungen werden• Storage darf nicht wiederverwendet werden• memcpy kann nicht verwendet werden• Type-Trait Optimierungen für PODs greifen nicht
• => • Trivialer Typ ist häufig erstrebenswert
Wichtig• Alle Funktionen werden mit „= default“ so erzeugt,
wie die automatisch generierten Funktionen erzeugt worden wären.
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 18 / 48
Typ ist trotz lauter expliziter spezieller Funktionen ein POD
struct Trivial
{
Trivial() = default;
Trivial(const Trivial&) = default;
Trivial(Trivial&&) = default;
Trivial& operator=(const Trivial&) = default;
Trivial& operator=(Trivial&&) = default;
~Trivial() = default;
};
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 19 / 48
Besonderheiten bei „explicitly defaulted functions“:• Variationen der speziellen Funktionen• constexpr• Default ausserhalb der Klassen-Definition
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 20 / 48
Variationen der speziellen Funktionen• Bei der Deklaration der speziellen Funktionen mit „= default“ sind nur
minimale Variationen erlaubt• Kopier-Konstruktor, Kopier-Zuweisungs-Operator, Move-Konstruktor und Move-
Zuweisungs-Operator dürfen auch non-const und/oder volatile Referenzen haben• Der Rückgabe-Typ der Zuweisungs-Operatoren ist nicht frei• Exception-Spezifikation muß matchen
• Parameter mit Default-Argumenten sind weder beim Standard-Konstruktor, Kopier-Konstruktor noch Move-Konstruktor mit „= default“ erlaubt
class A
{
public:
A(int=0) = default; // Fehler – Default-Argument
~A() throw(int) = default; // Fehler – Exceptions-Sp.
void operator=(A&&) = default; // Fehler - Rückgabe-Typ
A(A&) = default; // Okay, auch non-const Referenz
};
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 21 / 48
constexpr• Eine explizit defaulted Funktion kann nur „constexpr“ sein,
wenn es auch die normale automatische Funktion wäre
struct A
{
constexpr A() = default; // Fehler - constexpr
private:
int i;
};
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 22 / 48
Default ausserhalb der Klassen-Definition• Spezielle Funktionen können auch ausserhalb der Klassen-Definition explizit
defaulted werden• Achtung – solche Klassen sind dann niemals triviale Typen
• Denn unterschiedliche Nutzungs-Stellen könnten unterschiedliche Definitionen sehen
struct NonTrivial
{
NonTrivial();
};
NonTrivial:: NonTrivial() = default; // Okay
// Aber nicht trivial
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 23 / 48
Fazit• Sie können alle automatisch generierbaren speziellen Member-Funktionen
(ohne new & delete) in C++11 explizit default machen• Sie werden dann „normal“ generiert
• Daher triviale Typen bleiben triviale Typen• Damit können
• Unterdrückte automatische Generierungen wieder aktiviert werden• Zugriffsbereiche verändert werden• Virtuelle Destruktoren vereinfacht werden• Typen trivial gehalten werden
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 24 / 48
Deleted Functions
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 25 / 48
"= delete" hinter einer Funktion löscht diese Funktion• Damit kann man die Generierung von speziellen Funktionen unterdrücken
Haupt-Anwendung• Verbieten, dass ein Typ kopierbar und/oder movebar ist
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 26 / 48
Klassen sollten die Regel der 3, 4, 5, 6 oder 0 erfüllen Regel-der-3 - C++03
• Wenn eine Klasse einen expliziten Destruktor, Kopier-Konstruktor oder Kopier-Zuweisungs-Operator hat, dann ist es extrem wahrscheinlich das auch die anderen beiden speziellen Funktionen explizit definiert werden müssen.
Regel-der-4 - besseres C++03• Ohne eine typ-spezifische Swap-Funktion kann man den Kopier-Konstruktor
nur schwer sinnvoll und exception-sicher implementieren• Copy&Swap Idiom
Regel-der-5 - C++11• Regel-der-3 zusätzlich mit Move-Konstruktor und Move-Zuweisungs-Operator
Regel-der-6 - besseres C++11• Typ-spezifische Swap-Funktion ist ein Stück performanter als Swap mit Move
Regel-der-0 - C++11• Man nutzt RAII Klassen und benötigt keine spezielle Member-Funktion
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 27 / 48
Problem• Typ hat expliziten Destruktor, und die implizite Funktionen wie z.B. Kopier-
Konstruktor funktionieren nicht korrekt
Lösungen in C++03• Kopier-Konstruktor und -Zuweisungs-Operator privat deklarieren,
aber nicht implementieren• Beispiel siehe nächste Folie
• Klasse privat ableiten von boost::noncopyable• Beispiel siehe nächste Folie
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 28 / 48
class NonCopyable : boost::noncopyable // Achtung - kein POD
{
public:
// Impliziter Standard-Konstruktor ist auch nicht trivial
};
class NonCopyable // Achtung - kein POD
{
public:
NonCopyable() {} // Achtung - nicht trivial
private:
NonCopyable(const NonCopyable&); // ohne Impl.
NonCopyable& operator=(const NonCopyable&); // ohne Impl.
};
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 29 / 48
Nachteile• Standard-Konstruktor muß möglicherweise explizit gemacht werden
=> Standard-Konstruktor ist nicht trivial => kein POD• Friends und Member-Funktionen haben immer noch Zugriff
=> erst Linker-Fehler schlägt zu• Die Intention ist schwer zu verstehen
• Obwohl es ein akzeptiertes und verbreitetes Idiom ist
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 30 / 48
Lösung in C++11• Funktion mit "= delete" entfernen
class NonCopyable // Ist POD
{
public:
NonCopyable() = default; // Ist trivial
NonCopyable(const NonCopyable&) = delete;
NonCopyable& operator=(const NonCopyable&) = delete;
};
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 31 / 48
Vorteile• Standard-Konstruktor ist durch "= default" weiterhin trivial
=> Klasse kann also ein POD sein• Trotz Public-Funktionen gibt es beim Kopieren und Kopier-Zuweisen
immer einen Compiler-Fehler• Denn die Funktionen sind "deleted"
• Die Intention ist sofort klar
Hinweis• Der Typ "NonCopyable" ist auch nicht movebar• Denn die explizite Deklaration von z.B. dem Kopier-Konstruktor reicht
• Move-Konstruktor und -Zuweisungs-Operator werden nicht implizit erzeugt
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 32 / 48
Will man Typ haben, der movebar aber nicht kopierbar ist• Wie z.B. beim C++11 "std::unique_ptr"• Kopier-Operationen "deleten"• Move-Operationen "defaulten"
class OnlyMoveable
{
public:
OnlyMoveable() = default;
OnlyMoveable(const OnlyMoveable&) = delete;
OnlyMoveable& operator=(const OnlyMoveable&) = delete;
OnlyMoveable(OnlyMoveable&&) = default;
OnlyMoveable& operator=(OnlyMoveable&&) = default;
};
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 33 / 48
Aber es gibt auch noch andere Anwendungsfälle für = delete Z.B. eine Klasse, die nicht erzeugbar und zerstörbar ist
• Vielleicht als Sammlung von statischen Funktionen• Oder warum auch immer
=>• Standard-Konstruktor deleten• Optional auch noch deleten des Destruktors
• Aber eigentlich nicht notwändig
class A
{
public:
A() = delete;
~A() = delete;
};
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 34 / 48
Man kann nicht nur die speziellen Member-Funktionen deleten• Das geht auch für andere generierte Funktionen
• New & Delete Operatoren• Ganz normale Funktionen• Template-Funktionen
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 35 / 48
Deleten von New & Delete Operatoren• Typ läßt sich nicht dynamisch erstellen• Achtung - alle impliziten New-Varianten deleten (wenn gewollt)• "delete" muß nicht deleted werden - könnte man aber machen
class Type
{
public:
static void* operator new(std::size_t) = delete;
static void* operator new[](std::size_t) = delete;
static void* operator new(size_t, const nothrow_t&) noexcept = delete;
static void* operator new[](size_t, const nothrow_t&) noexcept = delete;
};
Type* p = new Type; // Compiler-Fehler
Type* q = new Type[4]; // Compiler-Fehler
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 36 / 48
Ganz normale Funktionen• Aber man kann auch ganz normale Funktionen deleten• Dann werden z.B. beim Überladen die entsprechenden Konvertierungen
unterbunden
void f(double);
void f(int) = delete;
f(3.14); // Okay
f(3); // Compiler-Fehler
// -> Exakt passende Funktion mit "int" ist "deleted"
// => keine Propagation zu "double"
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 37 / 48
Die normale Typ-Propagation ist dadurch nicht unterbunden• Double-Variante vorhanden• delete auf Float-Variante• =>
• Propagation auf double, die der float nicht abfängt, werden natürlich weiterhin durchgeführt
• Mit Templates läßt sich das verallgemeinern => siehe nächsten Folien
void f(double);
void f(float) = delete;
f(3.14); // Okay
f(3.14f); // Compiler-Fehler
f(3); // Okay - Propagation zu double
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 38 / 48
Variation mit Template-Funktion• Normale Funktion deleten• Template-Funktion anbieten
=>• Nun geht jeder Typ außer dem deleteten
• Natürlich mit der Template-Funktion
void f(double) = delete;
template<class T> void f(T) {}
f(3); // Okay
f("C++"s); // Okay
f(3.14); // Compiler-Fehler
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 39 / 48
Template-Funktionen• Erstellt man eine Template-Funktion und deleted sie, und überlädt sie mit
einer konkreten Funktion, so kann man die Funktion nur mit dem exakten Typ aufrufen
• Denn alle anderen Typen würden auf die Template-Funktion zurückgreifen, und die ist deleted.
void f(double);
template<class T> void f(T) = delete;
f(3.14); // Okay
f("C++"s); // Compiler-Fehler
f(3); // Compiler-Fehler
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 40 / 48
Besonderheiten bei Deleted Funktionen• Redundante deletes sind erlaubt• Deleted Funktionen sind implizit inline• Deleted Funktionen dürfen natürlich nicht nochmal definiert werden
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 41 / 48
Redundante deletes sind erlaubt• Daher deletes, die eigentlich nicht notwändig sind• Z.B. Standard-Konstruktor explizit deleten, obwohl anderer Konstruktor da ist
• Der implizite wird dann ja nicht erzeugt
class Type
{
public:
Type() = delete; // Redundant, aber okay
Type(int);
};
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 42 / 48
Deleted Funktionen sind implizit inline• Daher "= delete" muß in der Klassen-Definition stehen• Bei der "ersten Deklaration"• Sonst wäre es eine Verletzung der ODR
class Type
{
public:
Type();
};
Type::Type() = delete; // Compiler-Fehler
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 43 / 48
Deleted Funktionen dürfen nicht nochmal definiert werden• "= delete" entspricht einer Defintion• Würde anders ja auch keinen Sinn machen• Also anders als z.B. bei rein virtuellen Funktionen mit = 0
void fct(long) = delete;
void fct(long) { } // Compiler-Fehler
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 44 / 48
Fazit• Sie können alle Arten von Funktionen in C++11 deleten• Typischerweise wird dies für die speziellen Member-Funktionen gemacht
• Um Klassen nicht-kopierbar und/oder nicht moveable und/oder nicht dynamisch erzeugbar zu machen
• Außerdem kann man damit auch:• Überladungs-Fehler einschränken• Parameter-Propagationen verhindern• Template-Instanziierungen steuern
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 45 / 48
ISO & Links
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 46 / 48
C++11 Standard - ISO/IEC 14882• 8.4 Function definitions
• 8.4.1 In general• 8.4.2 Explicitly-defaulted functions• 8.4.3 Deleted definitions
• 12 Special member functions• 12.1 Constructors• 12.4 Destructors• 12.7 Construction and destruction• 12.8 Copying and moving class objects
• 13 Overloading• 13.5 Overloaded operators
13.5.3 Assignment
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 47 / 48
Links• http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2210.html • http://en.wikipedia.org/wiki/C%2B
%2B11#Explicitly_defaulted_and_deleted_special_member_functions • http://www.stroustrup.com/C++11FAQ.html#default• https://www.ibm.com/developerworks/community/blogs/5894415f-be62-
4bc0-81c5-3956e82276f3/entry/defaulted_functions_in_c_11?lang=en • http://msdn.microsoft.com/en-us/library/dn457344.aspx• http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=353• http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=354
C++11 Defaulted & Deleted Functions
http://www.wilkening-online.de 48 / 48
Danke