Skip to content
Menu
CDhistory
CDhistory

Move-konstruktorit

Posted on 26 toukokuun, 2021 by admin

Luokan T move-konstruktori on ei-mallinomainen konstruktori, jonka ensimmäinen parametri on T&&, const T&&, volatile T&& tai const volatile T&&, eikä muita parametreja ole, tai lopuilla parametreilla on kaikilla oletusarvot.

  • Sisältö
  • Syntaksi
  • Selitys
  • Implisiittisesti ilmoitettu move-konstruktori
  • Poistettu implisiittisesti ilmoitettu move-konstruktori
  • Triviaali move-konstruktori
  • Hyväksyttävä siirtokonstruktori
  • Implisiittisesti määritelty siirtokonstruktori
  • Huomautuksia
  • Esimerkki
  • Vikailmoitukset
  • Ks. myös

Sisältö

  • 1 Syntaksi
  • 2 Selitys
  • 3 Implisiittisesti ilmoitettu liikkeen konstruktori
  • 4 Poistettu implisiittisesti ilmoitettu liikkeen konstruktori
  • 5 Triviaalinen liikkeen konstruktori
  • 6 Tukikelpoinen liikkeen konstruktori
  • 7 Implisiittisesti-defined move constructor
  • 8 Huomautuksia
  • 9 Esimerkki
  • 10 Virheilmoitukset
  • 11 Katso myös

Syntaksi

class_name ( class_name && ) (1) (vuodesta C++11)
class_name ( class_name && ) = oletus; (2) (vuodesta C++11)
luokkanimi ( luokkanimi && ) = delete; (3) (C++11:stä lähtien)

Jossa class_name:n on nimettävä nykyinen luokka (tai luokkamallin tämänhetkinen instantiointi), tai kun se on deklaroitu nimiavaruuden vaikutusalueella tai friend-deklaraatiossa, sen on oltava kvalifioitu luokan nimi.

Selitys

1) Tyypillinen siirtokonstruktorin deklaraatio.
2) Pakottaa kääntäjän tuottamaan siirtokonstruktorin.
3) Välttää implisiittisen siirtokonstruktorin.

Move-konstruktoria kutsutaan tyypillisesti, kun objekti alustetaan (suoralla alustuksella tai kopioinnilla) samantyyppisestä rvalue- (xvalue- tai prvalue-) (C++17:ään asti)xvalue- (C++17:stä lähtien) -arvosta, mukaan lukien

  • alustaminen: T a = std::move(b); tai T a(std::move(b));, jossa b on tyyppiä T;
  • funktioargumenttien välitys: f(std::move(a));, jossa a on tyyppiä T ja f on void f(T t);
  • funktion return: return a; sisällä funktiossa, kuten T f(), jossa a on tyyppiä T, jolla on move-konstruktori.

Kun initiaattori on pr-arvo, move-konstruktorin kutsu optimoidaan usein pois (C++17:ään asti)ei koskaan tehdä (C++17:stä lähtien), ks. copy elision.

Move-konstruktorit tyypillisesti ”varastavat” argumentin hallussa olevat resurssit (esim.esim. osoittimet dynaamisesti varattuihin objekteihin, tiedoston kuvaajat, TCP-socketit, I/O-virrat, käynnissä olevat säikeet jne.) sen sijaan, että tekisivät niistä kopioita, ja jättävät argumentin johonkin kelvolliseen, mutta muuten määrittelemättömään tilaan. Esimerkiksi siirtyminen std::stringistä tai std::vectorista voi johtaa siihen, että argumentti jätetään tyhjäksi. Tähän käyttäytymiseen ei kuitenkaan pidä luottaa. Joillekin tyypeille, kuten std::unique_ptr:lle, siirretty tila on täysin määritelty.

Implisiittisesti ilmoitettu move-konstruktori

Jos luokkatyypille (struct, class tai union) ei ole annettu käyttäjän määrittelemiä move-konstruktoreita ja kaikki seuraavat ovat totta:

  • ei ole käyttäjän ilmoittamia kopiointikonstruktoreita;
  • ei ole käyttäjän ilmoittamia kopioinnin osoitusoperaattoreita;
  • ei ole käyttäjän ilmoittamia siirron osoitusoperaattoreita;
  • ei ole käyttäjän ilmoittamaa destruktoria.

tällöin kääntäjä ilmoittaa move-konstruktorin luokkansa ei-eksplisiittiseksi inline public jäseneksi allekirjoituksella T::T(T&&).

Luokalla voi olla useita move-konstruktoreita, esimerkiksi sekä T::T(const T&&) että T::T(T&&). Jos joitakin käyttäjän määrittelemiä move-konstruktoreita on olemassa, käyttäjä voi silti pakottaa implisiittisesti ilmoitetun move-konstruktorin tuottamisen avainsanalla default.

Implisiittisesti ilmoitetulla (tai ensimmäisellä ilmoituksella oletusarvoisesti ilmoitetulla) move-konstruktorilla on poikkeusmäärittely, joka on kuvattu dynaamisessa poikkeusmäärittelyssä (C++17:ään asti)poikkeusmäärittelyssä (C++17:stä lähtien)

Poistettu implisiittisesti ilmoitettu move-konstruktori

Luokan T implisiittisesti ilmoitettu (tai oletusarvoisesti ilmoitettu) move-konstruktori määritetään poistetuksi, jos mikä tahansa seuraavista on totta:

  • T:llä on ei-staattisia datajäseniä, joita ei voi siirtää (joilla on poistetut, saavuttamattomat tai epäselvät move-konstruktorit);
  • T:llä on suora tai virtuaalinen perusluokka, jota ei voi siirtää (jolla on poistetut, saavuttamattomat tai epäselvät move-konstruktorit);
  • T on suora tai virtuaalinen perusluokka, jolla on poistettu tai saavuttamattomissa oleva destruktori;
  • T on union-tyyppinen luokka ja sillä on muunnosjäsen, jolla on ei-triviaali siirtokonstruktori.

Ylikuormituksen resoluutio jättää huomiotta oletusarvoisen move-konstruktorin, joka on poistettu (muuten se estäisi kopiointi-initialisoinnin r-arvosta).

Triviaali move-konstruktori

Luokan T move-konstruktori on triviaali, jos kaikki seuraavista on totta:

  • se ei ole käyttäjän tarjoama (eli se on implisiittisesti määritelty tai oletusarvoinen);
  • T:llä ei ole virtuaalisia jäsenfunktioita;
  • T:llä ei ole virtuaalisia perusluokkia;
  • jokaiselle T:n suoralle kantafunktiolle valitulle siirtokonstruktorille on triviaali;
  • jokaiselle T:n ei-staattiselle luokkatyypin (tai luokkatyypin array) jäsenelle valitulle siirtokonstruktorille on triviaali.

Triviaali move-konstruktori on konstruktori, joka suorittaa saman toiminnon kuin triviaali kopiointikonstruktori, eli tekee kopion objektin esityksestä ikään kuin std::memmovella. Kaikki C-kielen kanssa yhteensopivat tietotyypit (POD-tyypit) ovat triviaalisti siirrettävissä.

Hyväksyttävä siirtokonstruktori

Siirtokonstruktori on hyväksyttävä, jos sitä ei ole poistettu.

(C++20:een asti)

Kelpoinen siirtokonstruktori on kelvollinen, jos

  • sitä ei poisteta ja
  • siihen liittyvät rajoitukset, jos sellaisia on, täyttyvät ja
  • yksikään saman ensimmäisen parametrin tyypin omaava siirtokonstruktori ei ole rajoitetumpi kuin se.
(C++20:sta lähtien)

Kelpoisten move-konstruktoreiden triviaalisuus määrittää, onko luokka implisiittisen elinajan tyyppi ja onko luokka triviaalisti kopioitavissa oleva tyyppi.

Implisiittisesti määritelty siirtokonstruktori

Jos implisiittisesti määritelty siirtokonstruktori ei ole poistettu eikä triviaali, kääntäjä määrittelee sen (eli generoi ja kääntää funktion rungon), jos se on odr-käytössä tai sitä tarvitaan vakion evaluointiin. Unionityypeille implisiittisesti määritelty move-konstruktori kopioi objektin esityksen (kuten std::memmove). Muiden kuin union-luokkatyyppien (class ja struct) osalta move-konstruktori suorittaa objektin emästen ja ei-staattisten jäsenten täyden jäsenkohtaisen siirron niiden alustamisjärjestyksessä käyttäen suoraa alustusta xvalue-argumentilla. Jos tämä täyttää constexpr-konstruktorin vaatimukset, generoitu move-konstruktori on constexpr.

Huomautuksia

Vahvan poikkeustakuun mahdollistamiseksi käyttäjän määrittelemät move-konstruktorit eivät saa heittää poikkeuksia. Esimerkiksi std::vector luottaa std::move_if_noexcept:iin valitessaan siirron ja kopioinnin välillä, kun elementtejä on siirrettävä.

Jos sekä copy- että move-konstruktorit on annettu, eivätkä muut konstruktorit ole käyttökelpoisia, ylikuormituksen resoluutio valitsee move-konstruktorin, jos argumentti on samantyyppinen r-arvo (x-arvo, kuten std::move:n tulos, tai pr-arvo, kuten nimetön väliaikainen (C++17:ään asti)), ja valitsee copy-konstruktorin, jos argumentti on l-arvo (nimetty objekti tai l-arvoviittauksen palauttava funktio/operaattori). Jos vain kopiointikonstruktori on annettu, kaikki argumenttiluokat valitsevat sen (kunhan se ottaa viittauksen constiin, koska rvalueet voivat sitoutua const-viittauksiin), mikä tekee kopioinnista varakeinon siirtämiselle, kun siirtäminen ei ole mahdollista.

Konstruktoria kutsutaan ’siirtämiskonstruktoriksi’, kun se ottaa parametrinaan rvalue-viittauksen. Sen ei ole pakko siirtää mitään, luokalla ei tarvitse olla siirrettävää resurssia ja ’move-konstruktori’ ei välttämättä pysty siirtämään resurssia kuten sallitussa (mutta ehkä ei järkevässä) tapauksessa, jossa parametrina on const rvalue-viittaus (const T&&).

Esimerkki

Suorita tämä koodi
#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);}

Tulos:

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

Vikailmoitukset

Seuraavia käyttäytymistä muuttavia vikailmoituksia sovellettiin takautuvasti aiemmin julkaistuihin C++ standardeihin.

DR Applied to Behavior as published Correct behavior
CWG 1402 C++11 poistettiin oletusarvoinen move-konstruktori, joka
kutsuisi ei-triviaalia kopiointikonstruktoria;
oletusarvoinen move-konstruktori, joka on poistettu
osallistui edelleen ylikuormitusratkaisuun
sallii kutsun tällaiselle kopiokonstruktorille;
ei huomioitu ylikuormituksen resoluutiossa
CWG 2094 C++11 haihtuva aliobjekti, joka on tehty oletusarvoisesta
liikkeen konstruktorista, joka ei oletriviaali (CWG496)
triviaalisuus ei vaikuta

Ks. myös

  • konstruktorin muuntaminen
  • kopiointikonstruktori
  • kopiointitehtävä
  • kopiointikonstruktori
  • copy elision
  • default constructor
  • destructor
  • explicit
  • initialization
    • aggregate initialization
    • vakioinitialisointi
    • kopioinitialisointi
    • oletusinitialisointi
    • suora inititialisointi
    • inititialisointiluettelo
    • luettelon inititialisointi
    • viittauksen inititialisointi
    • arvon inititialisointi
    • nollan inititialisointi
  • siirto allokointi
  • new

Vastaa Peruuta vastaus

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *

Viimeisimmät artikkelit

  • Acela on palannut: NYC tai Boston 99 dollarilla
  • Temple Fork Outfitters
  • Burr (romaani)
  • Trek Madone SLR 9 Disc
  • Jokainen valmistunut 2016 NBA:n vapaa agenttisopimus yhdessä paikassa

Arkistot

  • helmikuu 2022
  • tammikuu 2022
  • joulukuu 2021
  • marraskuu 2021
  • lokakuu 2021
  • syyskuu 2021
  • elokuu 2021
  • heinäkuu 2021
  • kesäkuu 2021
  • toukokuu 2021
  • huhtikuu 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