Skip to content
Menu
CDhistory
CDhistory

Move-konstruktører

Posted on maj 26, 2021 by admin

En move-konstruktør af klasse T er en ikke-skabelonkonstruktør, hvis første parameter er T&&, const T&&, volatile T&& eller const volatile T&&, og enten er der ingen andre parametre, eller også har resten af parametrene alle standardværdier.

  • Indhold
  • Syntaks
  • Forklaring
  • Implicit deklareret move-konstruktør
  • Slettet implicit-deklareret move-konstruktør
  • Triviel move-konstruktør
  • Støtteberettiget move-konstruktør
  • Implicit-defineret move-konstruktør
  • Bemærkninger
  • Eksempel
  • Fejlrapporter
  • Se også

Indhold

  • 1 Syntaks
  • 2 Forklaring
  • 3 Implicit deklareret flyttekonstruktør
  • 4 Slettet implicit deklareret flyttekonstruktør
  • 5 Triviel flyttekonstruktør
  • 6 Eligible flyttekonstruktør
  • 7 Implicit-defineret move-konstruktør
  • 8 Noter
  • 9 Eksempel
  • 10 Fejlrapporter
  • 11 Se også

Syntaks

class_name ( class_name && ) (1) (siden C++11)
class_name ( class_name && ) = standard; (2) (siden C++11)
class_name ( class_name && ) = delete; (3) (siden C++11)

Hvor class_name skal navngive den aktuelle klasse (eller den aktuelle instantiering af en klasseskabelon), eller, når den er erklæret i navnerumsområdet eller i en friend-deklaration, skal det være et kvalificeret klassenavn.

Forklaring

1) Typisk deklaration af en move-konstruktør.
2) Tvinger en move-konstruktør til at blive genereret af compileren.
3) Undgår implicit move-konstruktør.

Den move-konstruktør kaldes typisk, når et objekt initialiseres (ved direkte initialisering eller kopi-initialisering) fra rvalue (xvalue eller prvalue) (indtil C++17)xvalue (siden C++17) af samme type, herunder

  • initialisering: T a = std::move(b); eller T a(std::move(b)));;, hvor b er af typen T;
  • overdragelse af funktionsargumenter: f(std::move(a));;, hvor a er af typen T og f er void f(T t);
  • funktionsretur: return a; inde i en funktion som T f(), hvor a er af typen T, som har en move-konstruktør.

Når initialisatoren er en pr-værdi, er move-konstruktorkaldet ofte optimeret ud (indtil C++17)aldrig foretaget (siden C++17), se copy elision.

Move-konstruktører “stjæler” typisk de ressourcer, som argumentet har (f.eks.f.eks. pointers til dynamisk allokerede objekter, fildeskriptorer, TCP-socket, I/O-strømme, kørende tråde osv.) i stedet for at lave kopier af dem, og efterlader argumentet i en eller anden gyldig, men ellers ubestemt tilstand. F.eks. kan flytning fra en std::string eller fra en std::vector resultere i, at argumentet efterlades tomt. Man bør dog ikke stole på denne adfærd. For nogle typer, som f.eks. std::unique_ptr, er den flyttede tilstand fuldt specificeret.

Implicit deklareret move-konstruktør

Hvis der ikke er fastsat brugerdefinerede move-konstruktører for en klassetype (struct, class eller union), og alle følgende forhold er sande:

  • der er ingen brugerdeklarerede kopikonstruktører;
  • der er ingen brugerdeklarerede kopitildelingsoperatører;
  • der er ingen brugerdeklarerede flyttetildelingsoperatører;
  • der er ingen brugerdeklareret destruktor.

så vil compileren deklarere en move-konstruktør som et ikke-eksplicit inline public medlem af sin klasse med signaturen T::T(T&&).

En klasse kan have flere move-konstruktører, f.eks. både T::T(const T&&) og T::T(T&&). Hvis der findes nogle brugerdefinerede move-konstruktører, kan brugeren stadig tvinge genereringen af den implicit deklarerede move-konstruktør frem med nøgleordet default.

Den implicit-deklarerede (eller standardiserede ved dens første deklaration) move-konstruktør har en undtagelsesspecifikation som beskrevet i dynamisk undtagelsesspecifikation (indtil C++17)undtagelsesspecifikation (siden C++17)

Slettet implicit-deklareret move-konstruktør

Den implicit-deklarerede eller standardiserede move-konstruktør for klasse T er defineret som slettet, hvis en af følgende er sand:

  • T har ikke-statiske datamedlemmer, der ikke kan flyttes (har slettede, utilgængelige eller tvetydige move-konstruktører);
  • T har en direkte eller virtuel basisklasse, der ikke kan flyttes (har slettede, utilgængelige eller tvetydige move-konstruktører);
  • T har en direkte eller virtuel basisklasse med en slettet eller utilgængelig destruktor;
  • T er en union-lignende klasse og har et variantmedlem med en ikke-triviel flyttekonstruktør.

En standardiseret move-konstruktør, der er slettet, ignoreres af overload-opløsning (ellers ville det forhindre kopi-initialisering fra rvalue).

Triviel move-konstruktør

Men move-konstruktøren for klasse T er triviel, hvis alt det følgende er sandt:

  • den er ikke brugerforsynet (hvilket betyder, at den er implicit defineret eller standardiseret);
  • T har ingen virtuelle medlemsfunktioner;
  • T har ingen virtuelle basisklasser;
  • den valgte move-konstruktør for hver direkte base af T er triviel;
  • den valgte move-konstruktør for hvert ikke-statisk klassetype-medlem (eller array af klassetype-medlem) af T er triviel.

En trivial move-konstruktør er en konstruktør, der udfører den samme handling som den triviale copy-konstruktør, dvs. laver en kopi af objektrepræsentationen som ved std::memmove. Alle datatyper, der er kompatible med C-sproget (POD-typer), er trivielt flytbare.

Støtteberettiget move-konstruktør

En move-konstruktør er støtteberettiget, hvis den ikke er slettet.

(indtil C++20)

En flyttekonstruktør er kvalificeret, hvis

  • den ikke er slettet, og
  • dens tilknyttede begrænsninger, hvis der er nogen, er opfyldt, og
  • ingen flyttekonstruktør med samme første parametertype er mere begrænset end den.
(siden C++20)

Trivialitet af kvalificerede move-konstruktører bestemmer, om klassen er en implicit-lifetime-type, og om klassen er en trivielt kopierbar type.

Implicit-defineret move-konstruktør

Hvis den implicit-deklarerede move-konstruktør hverken er slettet eller triviel, defineres den (dvs. der genereres og kompileres en funktionskrop) af compileren, hvis den odr-bruges eller er nødvendig for konstant-evaluering. For unionstyper kopierer den implicit-definerede move-konstruktør objektrepræsentationen (som ved std::memmove). For ikke-union-klassetyper (class og struct) udfører move-konstruktøren en fuldstændig medlemsvis flytning af objektets baser og ikke-statiske medlemmer i deres initialiseringsrækkefølge ved hjælp af direkte initialisering med et xvalue-argument. Hvis dette opfylder kravene til en constexpr-konstruktør, er den genererede move-konstruktør constexpr.

Bemærkninger

For at gøre den stærke undtagelsesgaranti mulig bør brugerdefinerede move-konstruktører ikke kaste undtagelser. For eksempel er std::vector afhængig af std::move_if_noexcept for at vælge mellem move og copy, når elementerne skal flyttes.

Hvis der leveres både copy- og move-konstruktører, og ingen andre konstruktører er levedygtige, vælger overload-opløsning move-konstruktøren, hvis argumentet er en r-værdi af samme type (en x-værdi som f.eks. resultatet af std::move eller en pr-værdi som f.eks. en navnløs midlertidig (indtil C++17)), og vælger copy-konstruktøren, hvis argumentet er en l-værdi (navngivet objekt eller en funktion/operator, der returnerer en l-værdi-reference). Hvis kun copy-konstruktøren er angivet, vælger alle argumentkategorier den (så længe den tager en reference til const, da rværdier kan binde til const-referencer), hvilket gør kopiering til fallback for moving, når moving ikke er tilgængelig.

En konstruktør kaldes en “move-konstruktør”, når den tager en rvalue-reference som parameter. Den er ikke forpligtet til at flytte noget, klassen er ikke forpligtet til at have en ressource, der skal flyttes, og en ‘move-konstruktør’ er måske ikke i stand til at flytte en ressource som i det tilladte (men måske ikke fornuftige) tilfælde, hvor parameteren er en const rvalue-reference (const T&&).

Eksempel

Kør denne kode
#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);}

Output:

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

Fejlrapporter

De følgende adfærdsændrende fejlrapporter blev anvendt med tilbagevirkende kraft på tidligere offentliggjorte C++-standarder.

DR Anvendt på Adfærd som offentliggjort Korrekt adfærd
CWG 1402 C++11 en standardiseret move-konstruktør, der ville
anråbe en ikke-triviel kopi-konstruktør, blev slettet;
en standardiseret move-konstruktør, der er slettet
, deltog stadig i overload-opløsningen
tillader kald til en sådan kopikonstruktør;
gjorde ignoreret i overload-opløsning
CWG 2094 C++11 et flygtigt underobjekt lavet af en defaulted
move-konstruktør, der ikketrivial (CWG496)
trivialitet ikke påvirket

Se også

  • konvertere konstruktør
  • kopi-tildeling
  • kopikopieringskonstruktør
  • kopi-elision
  • standardkonstruktor
  • destruktor
  • eksplicit
  • initialisering
    • aggregeret initialisering
    • konstant initialisering
    • kopiinitialisering
    • standardinitialisering
    • direkte initialisering
    • initialiseringsliste
    • listeinitialisering
    • referenceinitialisering
    • referenceinitialisering
    • værdiinitialisering
    • nulinitialisering
  • flytte tildeling
  • ny

Skriv et svar Annuller svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *

Seneste indlæg

  • Acela er tilbage:
  • OMIM Entry – # 608363 – CHROMOSOM 22q11.2 DUPLIKATIONSSYNDROM
  • Kate Albrechts forældre – Få mere at vide om hendes far Chris Albrecht og mor Annie Albrecht
  • Temple Fork Outfitters
  • Burr (roman)

Arkiver

  • februar 2022
  • januar 2022
  • december 2021
  • november 2021
  • oktober 2021
  • september 2021
  • august 2021
  • juli 2021
  • juni 2021
  • maj 2021
  • april 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