Skip to content
Menu
CDhistory
CDhistory

Pohybové konstruktory

Posted on 26 května, 2021 by admin

Pohybový konstruktor třídy T je nešablonový konstruktor, jehož první parametr je T&&, const T&&, volatile T&& nebo const volatile T&& a buď nemá žádné další parametry, nebo mají všechny ostatní parametry výchozí hodnoty.

  • Obsah
  • Syntaxe
  • Vysvětlení
  • Implicitně deklarovaný konstruktor move
  • Odstraněný implicitně deklarovaný move konstruktor
  • Triviální konstruktor přesunu
  • Způsobilý konstruktor přesunu
  • Implicitně definovaný move konstruktor
  • Poznámky
  • Příklad
  • Zprávy o závadách
  • Viz také

Obsah

  • 1 Syntaxe
  • 2 Vysvětlení
  • 3 Implicitně deklarovaný konstruktor move
  • 4 Odstraněný implicitně deklarovaný konstruktor move
  • 5 Triviální konstruktor move
  • 6 Způsobilý konstruktor move
  • 7 Implicitně-definovaný move konstruktor
  • 8 Poznámky
  • 9 Příklad
  • 10 Hlášení závad
  • 11 Viz také

Syntaxe

class_name ( class_name && ) (1) (od C++11)
class_name ( class_name && ) = výchozí; (2) (od C++11)
class_name ( class_name && ) = delete; (3) (od C++11)

Kde class_name musí pojmenovávat aktuální třídu (nebo aktuální instanci šablony třídy), nebo, je-li deklarováno v oboru jmenného prostoru nebo v deklaraci přítele, musí být kvalifikovaným jménem třídy.

Vysvětlení

1) Typická deklarace konstruktoru move.
2) Vynucení generování konstruktoru move kompilátorem.
3) Vyhnutí se implicitnímu konstruktoru move.

Konstruktor move se typicky volá při inicializaci objektu (přímou inicializací nebo kopírováním) z rvalue (xvalue nebo prvalue) (do C++17)xvalue (od C++17) stejného typu, včetně

  • inicializace: T a = std::move(b); nebo T a(std::move(b));, kde b je typu T;
  • předávání argumentů funkce: f(std::move(a));, kde a je typu T a f je void f(T t);
  • návrat funkce: return a; uvnitř funkce jako T f(), kde a je typu T, která má konstruktor move.

Pokud je inicializátorem prvalue, volání move konstruktoru se často optimalizuje (do C++17)nikdy se neprovádí (od C++17), viz copy elision.

Move konstruktory typicky „kradou“ prostředky držené argumentem (např.např. ukazatele na dynamicky alokované objekty, deskriptory souborů, TCP sokety, I/O proudy, běžící vlákna atd.), místo aby vytvářely jejich kopie, a ponechávají argument v nějakém platném, ale jinak neurčitém stavu. Například přechod ze std::string nebo ze std::vector může vést k tomu, že argument zůstane prázdný. Na toto chování by se však nemělo spoléhat. U některých typů, jako je například std::unique_ptr, je stav přesunu z plně specifikován.

Implicitně deklarovaný konstruktor move

Pokud pro typ třídy (struct, class nebo union) nejsou k dispozici žádné uživatelsky definované konstruktory move a platí všechny následující podmínky:

  • nejsou žádné uživatelsky deklarované kopírovací konstruktory;
  • nejsou žádné uživatelsky deklarované operátory přiřazení kopií;
  • nejsou žádné uživatelsky deklarované operátory přiřazení přesunů;
  • není žádný uživatelsky deklarovaný destruktor.

tak kompilátor deklaruje konstruktor přesunu jako neexplicitní inline public člen své třídy se signaturou T::T(T&&).

Třída může mít více konstruktorů přesunu, např. jak T::T(const T&&), tak T::T(T&&). Pokud jsou přítomny některé uživatelem definované konstruktory pohybu, může si uživatel ještě vynutit vygenerování implicitně deklarovaného konstruktoru pohybu pomocí klíčového slova default.

Implicitně deklarovaný (nebo při první deklaraci výchozí) move konstruktor má specifikaci výjimky popsanou ve specifikaci dynamických výjimek (do C++17)specifikaci výjimek (od C++17)

Odstraněný implicitně deklarovaný move konstruktor

Implicitně deklarovaný nebo výchozí move konstruktor pro třídu T je definován jako odstraněný, pokud je pravdivá některá z následujících hodnot:

  • T má nestatické datové členy, které nelze přesunout (mají smazané, nedostupné nebo nejednoznačné move konstruktory);
  • T má přímou nebo virtuální základní třídu, kterou nelze přesunout (má smazané, nedostupné nebo nejednoznačné move konstruktory);
  • T má přímou nebo virtuální bázovou třídu se smazaným nebo nedostupným destruktorem;
  • T je třída podobná unii a má variantní člen s netriviálním konstruktorem přesunu.

Defaultní konstruktor move, který je smazán, je ignorován při řešení přetížení (jinak by zabránil kopírování inicializace z rvalue).

Triviální konstruktor přesunu

Konstruktor přesunu pro třídu T je triviální, pokud platí všechny následující podmínky:

  • není uživatelský (to znamená, že je implicitně definovaný nebo výchozí);
  • T nemá žádné virtuální členské funkce;
  • T nemá žádné virtuální základní třídy;
  • konstruktor pohybu vybraný pro každou přímou bázi T je triviální;
  • konstruktor pohybu vybraný pro každý nestatický člen typu třídy (nebo pole typu třídy) T je triviální.

Triviální move konstruktor je konstruktor, který provádí stejnou akci jako triviální kopírovací konstruktor, tj. vytváří kopii reprezentace objektu jako pomocí std::memmove. Všechny datové typy kompatibilní s jazykem C (typy POD) jsou triviálně přesunutelné.

Způsobilý konstruktor přesunu

Konstruktor přesunu je způsobilý, pokud není smazán.

(do C++20)

Konstruktor přesunu je způsobilý, jestliže

  • není smazán a
  • jsou splněna jeho případná přidružená omezení a
  • žádný konstruktor přesunu se stejným typem prvního parametru není více omezen než on.
(od C++20)

Trivialita způsobilých konstruktérů přesunu určuje, zda je třída implicitně-životním typem a zda je třída triviálně kopírovatelným typem.

Implicitně definovaný move konstruktor

Jestliže implicitně deklarovaný move konstruktor není ani smazatelný, ani triviální, je definován (tj. je vygenerováno a zkompilováno tělo funkce) kompilátorem, je-li odr-užit nebo potřebný pro vyhodnocení konstanty. Pro typy union implicitně definovaný konstruktor move kopíruje reprezentaci objektu (jako u std::memmove). U nesjednocených třídních typů (class a struct) provádí konstruktor move úplný přesun bází a nestatických členů objektu v jejich inicializačním pořadí pomocí přímé inicializace s argumentem xvalue. Pokud toto splňuje požadavky konstruktoru constexpr, je vygenerovaný konstruktor move constexpr.

Poznámky

Aby bylo možné zaručit silné výjimky, neměly by uživatelsky definované konstruktory move vyhazovat výjimky. Například std::vector spoléhá na std::move_if_noexcept, aby se rozhodl mezi move a copy, když je třeba prvky přemístit.

Jsou-li k dispozici konstruktory copy i move a žádné jiné konstruktory nejsou životaschopné, rozlišení přetížení vybere konstruktor move, pokud je argumentem rvalue stejného typu (xvalue, například výsledek std::move, nebo prvalue, například bezejmenný temporary (do C++17)), a vybere konstruktor copy, pokud je argumentem lvalue (pojmenovaný objekt nebo funkce/operátor vracející odkaz na lvalue). Pokud je uveden pouze kopírovací konstruktor, vyberou jej všechny kategorie argumentů (pokud přebírá referenci na const, protože rvalues se mohou vázat na reference const), čímž se kopírování stává nouzovým řešením pro přesun, pokud přesun není k dispozici.

Konstruktor se nazývá „přesunovací konstruktor“, pokud jako parametr přebírá referenci na rvalue. Není povinen nic přesouvat, třída nemusí mít prostředek, který má být přesunut, a ‚move konstruktor‘ nemusí být schopen přesunout prostředek jako v přípustném (ale možná ne rozumném) případě, kdy je parametrem const rvalue reference (const T&&).

Příklad

Spustit tento kód
#include <string>#include <iostream>#include <iomanip>#include <utility> struct A{ std::string s; int k; A() : s("test"), k(-1) { } A(const A& o) : s(o.s), k(o.k) { std::cout << "move failed!\n"; } A(A&& o) noexcept : s(std::move(o.s)), // explicit move of a member of class type k(std::exchange(o.k, 0)) // explicit move of a member of non-class type { }}; A f(A a){ return a;} struct B : A{ std::string s2; int n; // implicit move constructor B::(B&&) // calls A's move constructor // calls s2's move constructor // and makes a bitwise copy of n}; struct C : B{ ~C() { } // destructor prevents implicit move constructor C::(C&&)}; struct D : B{ D() { } ~D() { } // destructor would prevent implicit move constructor D::(D&&) D(D&&) = default; // forces a move constructor anyway}; int main(){ std::cout << "Trying to move A\n"; A a1 = f(A()); // return by value move-constructs the target from the function parameter std::cout << "Before move, a1.s = " << std::quoted(a1.s) << " a1.k = " << a1.k << '\n'; A a2 = std::move(a1); // move-constructs from xvalue std::cout << "After move, a1.s = " << std::quoted(a1.s) << " a1.k = " << a1.k << '\n'; std::cout << "Trying to move B\n"; B b1; std::cout << "Before move, b1.s = " << std::quoted(b1.s) << "\n"; B b2 = std::move(b1); // calls implicit move constructor std::cout << "After move, b1.s = " << std::quoted(b1.s) << "\n"; std::cout << "Trying to move C\n"; C c1; C c2 = std::move(c1); // calls copy constructor std::cout << "Trying to move D\n"; D d1; D d2 = std::move(d1);}

Výstup:

Trying to move ABefore move, a1.s = "test" a1.k = -1After move, a1.s = "" a1.k = 0Trying to move BBefore move, b1.s = "test"After move, b1.s = ""Trying to move Cmove failed!Trying to move D

Zprávy o závadách

Následující zprávy o závadách měnících chování byly zpětně aplikovány na dříve vydané normy C++.

DR Aplikováno na Chování ve zveřejněné podobě Správné chování
CWG 1402 C++11 byl odstraněn výchozí konstruktor move, který by
volal netriviální konstruktor copy;
přednastavený konstruktor přesunu, který byl odstraněn
, se stále podílel na řešení přetížení
umožňuje volání takového kopírovacího konstruktoru;
byl ignorován při řešení přetížení
CWG 2094 C++11 volatilní podobjekt vytvořený z defaultního
konstruktoru přesunu, který nenítriviální (CWG496)
trivialita není dotčena

Viz také

  • konvertující konstruktor
  • kopírující přiřazení
  • kopírující konstruktor
  • kopírování elize
  • výchozí konstruktor
  • destruktor
  • explicitní
  • inicializace
    • souhrnná inicializace
    • konstantní inicializace
    • kopírovací inicializace
    • výchozí inicializace
    • přímá inicializace
    • inicializátor seznamu
    • inicializace seznamu
    • referenční inicializace
    • inicializace hodnoty
    • nulová inicializace
  • přiřazení pohybu
  • nový

Napsat komentář Zrušit odpověď na komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *

Nejnovější příspěvky

  • Acela je zpět:
  • OMIM záznam – # 608363 – CHROMOSOM 22q11.2 DUPLICATION SYNDROME
  • Rodiče Kate Albrechtové – více o jejím otci Chrisu Albrechtovi a matce Annie Albrechtové
  • Temple Fork Outfitters
  • Burr (román)

Archivy

  • Únor 2022
  • Leden 2022
  • Prosinec 2021
  • Listopad 2021
  • Říjen 2021
  • Září 2021
  • Srpen 2021
  • Červenec 2021
  • Červen 2021
  • Květen 2021
  • Duben 2021
  • DeutschDeutsch
  • NederlandsNederlands
  • SvenskaSvenska
  • DanskDansk
  • EspañolEspañol
  • FrançaisFrançais
  • PortuguêsPortuguês
  • ItalianoItaliano
  • RomânăRomână
  • PolskiPolski
  • ČeštinaČeština
  • MagyarMagyar
  • SuomiSuomi
  • 日本語日本語
©2022 CDhistory | Powered by WordPress & Superb Themes