Explicitně přednastavené a odstraněné funkce
V C ++ 11 výchozí a odstraněné funkce poskytují explicitní kontrolu, nad tím, zda jsou automaticky generovány zvláštní členské funkce.Odstraněné funkce také poskytují jednoduchý jazyk, který má zabránit propagace problematických typu z, ke kterým došlo v argumenty funkce všech typů – speciální členské funkce, stejně jako normální členské funkce a funkce třetí – což by jinak způsobit volání funkce nežádoucí.
Výhody explicitně nastavených a odstraněných funkcí
V jazyce C++ kompilátor automaticky generuje výchozí konstruktor, kopie konstruktoru, operátor přiřazení kopie a destruktor typu pokud ji neobsahuje deklaraci vlastní.Tyto funkce jsou známy jako zvláštní členské funkce a díky nim se jednoduché typy definované uživatelem v jazyce C++ chovají jako struktury v jazyce C.Můžete je tedy vytvořit, kopírovat a zničit bez jakéhokoli dalšího kódování.11 C ++ přináší přesunutí sémantiky jazyka a přidá konstruktor přesunout a operátor přiřazení přesunout do seznamu členů speciální funkce, které může kompilátor automaticky generovat.
Tato možnost je pohodlná pro jednoduché typy, ale komplexní typy často definují jednu nebo více zvláštních členských funkcí jako takových, a to může zabránit automatickému generování dalších zvláštních členských funkcí.V praxi:
Pokud je explicitně deklarovány žádné konstruktoru, žádný výchozí konstruktor automaticky generována.
Pokud je virtuální destruktor explicitně deklarovány, žádné výchozí destruktor automaticky generována.
Pokud přesunutí konstruktor nebo operátor přiřazení přesunout výslovně deklarována, pak:
Žádný konstruktor kopie není automaticky vygenerován.
Žádný operátor přiřazení kopie není automaticky vygenerován.
Pokud kopie konstruktoru operátor přiřazení kopie konstruktoru, operátor přiřazení přesunout přesunutí nebo destruktor je explicitně deklarovány, pak:
Žádný konstruktor přesunu není automaticky vygenerován.
Žádný operátor přiřazení přesunu není automaticky vygenerován.
[!POZNÁMKA]
Navíc C ++ 11 standard určuje další následující pravidla:
Pokud Kopírovat konstruktor a destruktor explicitně deklarovány, automatické generování operátor přiřazení kopie je zastaralý.
Je-li operátor přiřazení kopie nebo destruktor explicitně deklarovaný, pak automatické generování kopie konstruktoru je zastaralý.
V obou případech Visual Studio automaticky generovat nezbytné funkce implicitně i nadále a ne posílat upozornění.
Důsledky těchto pravidel může také způsobit únik do hierarchií objektu.Například, pokud z nějakého důvodu nepodaří mít výchozí konstruktor, který lze volat z odvozená třída základní třídy – to znamená, public nebo protected konstruktor, který nepřijímá žádné parametry – bude třídu, která pochází z něj nelze automaticky generovat své vlastní výchozí konstruktor.
Tato pravidla mohou zkomplikovat implementaci toho, co by mělo být jasné, uživatelem definované typy a společné idiomy v jazyce C++ – například vytvoření uživatelem definovaného typu, který nelze zkopírovat deklarováním konstruktoru a operátoru přiřazení kopie soukromě a nikoli jejich definováním.
struct noncopyable
{
noncopyable() {};
private:
noncopyable(const noncopyable&);
noncopyable& operator=(const noncopyable&);
};
Před C++11 byl tento fragment kódu idiomatickou formou nekopírovatelných typů.Má však několik problémů:
Konstruktor kopie je třeba deklarovat soukromě a tak jej skrýt, ale protože je celkově deklarován, automatickému generování výchozího konstruktoru je zabráněno.Je nutné explicitně definovat výchozí konstruktor, chcete-li nějaký používat, i když to nemá žádný účinek.
I v případě, že explicitně definovaný výchozí konstruktor neprovede žádnou akci, kompilátor ho považuje za netriviální.Je méně efektivní než automaticky generované výchozí konstruktor a zabraňuje noncopyable z právě POD typu true.
I když jsou skryté konstruktor kopie a operátor přiřazení kopie z vnější kódu, funkce členů a přátelé noncopyable stále vidíte a můžete volat je.Pokud jsou deklarovány, ale nejsou definovány, jejich volání způsobí chybu linkeru.
Ačkoli se jedná o obecně uznávaný idiom, záměr není jasný, pokud neznáte všechna pravidla pro automatické generování zvláštních členských funkcí.
V C ++ 11-kopírovatelná idiomu prováděna způsobem, který je přímější.
struct noncopyable
{
noncopyable() =default;
noncopyable(const noncopyable&) =delete;
noncopyable& operator=(const noncopyable&) =delete;
};
Všimněte si, jak se řeší problémy v idiomu verze starší, než C ++ 11:
Generace výchozí konstruktor stále brání deklaraci konstruktoru kopie, ale můžete přenést zpět pomocí příkazu explicitně ji.
Výslovně nastavená výchozí člen speciální funkce jsou stále považovány za bezvýznamné, tedy žádné snížení výkonu a noncopyable není zabráněno TrueType LUSKU.
Konstruktor kopie a operátor přiřazení kopie jsou veřejné, ale odstraněny.Jedná se o chybu v době kompilace při definici nebo volání odstraněné funkce.
Záměrem je jasné každému, kdo chápe, =default a =delete.Nemusíte pochopit pravidla pro automatické generování speciálních členských funkcí.
Podobné idiomy existují pro vytvoření uživatelem definovaných typů, které jsou nepohyblivé, které mohou být pouze dynamicky přiřazovány nebo které nelze dynamicky přidělit.Každý z těchto idiomů má předimplementace C++11, které trpí podobnými problémy a které jsou podobně řešeny v C++11 jejich implementací z hlediska výchozích a odstraněných speciálních členských funkcí.
Explicitně nastavena výchozí hodnota funkce
Můžete nastavit jako výchozí jakékoli zvláštní členské funkce – k výslovnému uvedení, že zvláštní členská funkce používá výchozí implementace k definování zvláštní členské funkce s neveřejným kvalifikátorem veřejného přístupu, nebo obnovit zvláštní členskou funkci, k jejímuž automatickému generování nedošlo z důvodu jiné okolnosti.
Speciální funkci prvku nastavíte na výchozí stav deklarováním jako v následujícím příkladu:
struct widget
{
widget()=default;
inline widget& operator=(const widget&);
};
inline widget& widget::operator=(const widget&) =default;
Všimněte si, že můžete použít výchozí nastavení pro zvláštní členské funkce mimo tělo třídy za podmínky, že jsou vložitelné.
Protože výkony těží z triviálních zvláštních členských funkcí, doporučujeme raději automaticky generovat zvláštní členské funkce nad prázdnými funkcemi, pokud chcete výchozí chování.To lze provést explicitním nastavením speciální výchozí funkce člena nebo nedeklarováním (a také nedeklarováním dalších speciálních členských funkcí, které by zabránily automatickému generování deklarace.)
[!POZNÁMKA]
Visual Studionepodporuje přesunutí výchozí konstruktory nebo přesunout přiřazení operátorů jako C ++ 11 standardní pověření.Další informace naleznete v oddílu Používání výchozích a odstraněných funkcí v tématu Podpora funkcí C++11 (moderní jazyk C++).
Odstraněné funkce
Můžete odstranit speciální členské funkce stejně jako normální členské funkce a nečlenské funkce a zabránit tak jejich definování nebo volání.Odstranění zvláštních členských funkcí umožňuje čistší způsob zabránění kompilátoru generovat speciálních členské funkce, které nechcete.Funkce musí být odstraněn, protože je deklarovaná; nelze jej později odstranit způsobem, můžete funkce deklarované a později převezme.
struct widget
{
// deleted operator new prevents widget from being dynamically allocated.
void* operator new(std::size_t) =delete;
};
Odstraňování běžné členské funkce nebo nečlenských funkcí zabraňuje problematickým propagacím způsobovat volání nežádoucích funkcí.Tento postup funguje, protože odstraněné funkce se stále účastní na rozlišení přetížení a poskytnutí lepší shody než funkce, kterou lze volat po propagaci typů.Volání funkce převede na více specifických, ale odstraněné – funkce a způsobí chybu kompilátoru.
// deleted overload prevents call through type promotion of float to double from succeeding.
void call_with_true_double_only(float) =delete;
void call_with_true_double_only(double param) { return; }
V předchozím příkladu si všimněte volání call_with_true_double_only pomocí float argument způsobí chybu kompilátoru, ale volání call_with_true_double_only pomocí int argument by; v int případě argument bude povýšen z int k double a úspěšně volat double verze funkce, i když, možná co je určen.Chcete-li zajistit, že jakékoli volání této funkce pomocí jiných double argument způsobí chybu kompilátoru, můžete deklarovat verze šablony funkce, kterou se zrušuje.
template < typename T >
void call_with_true_double_only(T) =delete; //prevent call through type promotion of any T to double from succeeding.
void call_with_true_double_only(double param) { return; } // also define for const double, double&, etc. as needed.