Skip to content
Menu
CDhistory
CDhistory

Mozgó konstruktorok

Posted on május 26, 2021 by admin

A T osztály mozgató konstruktora olyan nem sablon konstruktor, amelynek első paramétere T&&, const T&&, volatile T&& vagy const volatile T&&, és vagy nincs más paraméter, vagy a többi paraméter mind alapértelmezett értékű.

  • tartalom
  • Szintaxis
  • Magyarázat
  • Implicit módon deklarált move-konstruktor
  • Törölt implicit módon deklarált mozdulat-konstruktor
  • Triviális mozgatás-konstruktor
  • Jogosult mozgatható konstruktor
  • Implicit módon definiált mozgáskonstruktor
  • Megjegyzések
  • Példa
  • Hibajelentések
  • Lásd még

tartalom

  • 1 Szintaxis
  • 2 Magyarázat
  • 3 Implicit módon deklarált mozdulat-konstruktor
  • 4 Törölt implicit módon deklarált mozdulat-konstruktor
  • 5 Triviális mozdulat-konstruktor
  • 6 Eligazítható mozdulat-konstruktor
  • 7 Implicit módon-definiált mozgatási konstruktor
  • 8 Megjegyzések
  • 9 Példa
  • 10 Hibajelentések
  • 11 Lásd még

Szintaxis

class_name ( class_name && ) (1) (C++11 óta)
class_name ( class_name && ) = default; (2) (C++11 óta)
class_name ( class_name && ) = delete; (3) (C++11 óta)

Ahol a class_name-nek az aktuális osztályt (vagy egy osztálysablon aktuális példányát) kell megneveznie, vagy ha névtérhatáron vagy friend deklarációban deklarálják, akkor minősített osztálynévnek kell lennie.

Magyarázat

1) Mozgóképző tipikus deklarálása.
2) A fordító által generált mozgóképző kikényszerítése.
3) Implicit mozgóképző elkerülése.

A move-konstruktort jellemzően akkor hívjuk meg, amikor egy objektumot inicializálunk (közvetlen inicializálással vagy másolásos inicializálással) rvalue (xvalue vagy prvalue) (C++17-ig)xvalue (C++17 óta) azonos típusból, beleértve a

  • inicializálást is: T a = std::move(b); vagy T a(std::move(b));;, ahol b típusú T;
  • függvény argumentumátadás: f(std::move(a));;, ahol a T típusú és f void f(T t);
  • függvény visszatérése: return a; egy olyan függvényen belül, mint például T f(), ahol a T típusú, amely rendelkezik move konstruktorral.

Ha az inicializáló egy prvalue, a move konstruktor hívása gyakran optimalizálva van (C++17-ig)soha nem történik (C++17 óta), lásd copy elision.

A move konstruktorok jellemzően “ellopják” az argumentum által tartott erőforrásokat (pl.pl. dinamikusan kiosztott objektumokra mutató mutatókat, fájlleírókat, TCP aljzatokat, I/O folyamokat, futó szálakat stb.) ahelyett, hogy másolatokat készítenének róluk, és az argumentumot valamilyen érvényes, de egyébként meghatározhatatlan állapotban hagyják. Például egy std::stringből vagy egy std::vektorból való áthelyezés azt eredményezheti, hogy az argumentum üresen marad. Erre a viselkedésre azonban nem szabad támaszkodni. Néhány típus esetében, mint például az std::unique_ptr, az áthelyezett állapot teljesen meghatározott.

Implicit módon deklarált move-konstruktor

Ha egy osztálytípushoz (struct, class vagy union) nincsenek felhasználó által definiált move-konstruktorok megadva, és az alábbiak mindegyike igaz:

  • nincsenek felhasználó által deklarált másolási konstruktorok;
  • nincsenek felhasználó által deklarált másolási hozzárendelési operátorok;
  • nincsenek felhasználó által deklarált mozgatási hozzárendelési operátorok;
  • nincs felhasználó által deklarált destruktor.

akkor a fordító a move konstruktort az osztály nem explicit inline public tagjaként deklarálja T::T(T&&) aláírással.

Egy osztálynak több move konstruktora is lehet, például mind a T::T(const T&&), mind a T::T(T&&). Ha van néhány felhasználó által definiált move-konstruktor, a felhasználó a default kulcsszóval még kikényszerítheti az implicit módon deklarált move-konstruktor létrehozását.

Az implicit módon deklarált (vagy az első deklarációjánál alapértelmezett) mozdulat-konstruktor a dinamikus kivételi specifikációban (C++17-ig)exception specification (C++17 óta)

Törölt implicit módon deklarált mozdulat-konstruktor

A T osztály implicit módon deklarált vagy alapértelmezett mozdulat-konstruktora töröltnek minősül, ha az alábbiak bármelyike igaz:

  • T nem statikus adattagokkal rendelkezik, amelyek nem mozgathatók (törölt, elérhetetlen vagy kétértelmű mozgató konstruktorral rendelkeznek);
  • T közvetlen vagy virtuális bázisosztálya van, amely nem mozgatható (törölt, elérhetetlen vagy kétértelmű mozgató konstruktorral rendelkezik);
  • T közvetlen vagy virtuális alaposztálya törölt vagy hozzáférhetetlen destruktorral rendelkezik;
  • T union-szerű osztály, és van egy variáns tagja nem triviális mozgatási konstruktorral.

A törölt alapértelmezett move konstruktort a túlterhelésfeloldás figyelmen kívül hagyja (különben megakadályozná a másolás-inicializálást az rvalue-ból).

Triviális mozgatás-konstruktor

A T osztály mozgatás-konstruktora triviális, ha az alábbiak közül mindegyik igaz:

  • nem felhasználó által biztosított (vagyis implicit módon definiált vagy alapértelmezett);
  • T nem rendelkezik virtuális tagfüggvényekkel;
  • T nem rendelkezik virtuális bázisosztályokkal;
  • a T minden közvetlen bázisához kiválasztott mozgató konstruktor triviális;
  • a T minden nem statikus osztálytípusú (vagy osztálytípusú tömb) tagjához kiválasztott mozgató konstruktor triviális.

A triviális move konstruktor olyan konstruktor, amely ugyanazt a műveletet hajtja végre, mint a triviális copy konstruktor, azaz másolatot készít az objektum reprezentációjáról, mintha az std::memmove segítségével tenné. Minden C nyelvvel kompatibilis adattípus (POD típusok) triviálisan mozgatható.

Jogosult mozgatható konstruktor

Egy mozgatható konstruktor akkor jogosult, ha nem törölhető.

(C++20-ig)

Egy mozgatás-konstruktor akkor alkalmas, ha

  • nem törölték, és
  • a hozzá tartozó korlátozások, ha vannak, teljesülnek, és
  • nincs olyan mozgatás-konstruktor, amelynek azonos első paramétertípusa jobban korlátozott, mint neki.
(C++20 óta)

A jogosult mozdulat-konstruktorok trivialitása határozza meg, hogy az osztály implicit élettartamú típus-e, és hogy az osztály triviálisan másolható típus-e vagy sem.

Implicit módon definiált mozgáskonstruktor

Ha az implicit módon deklarált mozgáskonstruktor nem törölhető és nem triviális, akkor a fordító definiálja (azaz függvénytestet generál és fordít), ha odr-használat vagy konstanskiértékeléshez szükséges. Union típusok esetén az implicit módon definiált move konstruktor másolja az objektum reprezentációját (mint az std::memmove). A nem uniós osztálytípusok (class és struct) esetében a move konstruktor az objektum bázisainak és nem statikus tagjainak teljes tagonkénti mozgatását végzi el, inicializálási sorrendjükben, közvetlen inicializálással, xvalue argumentummal. Ha ez megfelel a constexpr konstruktorral szemben támasztott követelményeknek, akkor a generált move konstruktor constexpr.

Megjegyzések

Az erős kivételgarancia lehetővé tétele érdekében a felhasználó által definiált move konstruktorok nem dobhatnak kivételeket. Például az std::vector az std::move_if_noexceptre támaszkodik, hogy válasszon a move és a copy között, amikor az elemeket át kell helyezni.

Ha mind a copy, mind a move konstruktorok meg vannak adva, és más konstruktor nem életképes, a túlterhelés feloldás a move konstruktort választja, ha az argumentum egy azonos típusú r-érték (egy x-érték, például az std::move eredménye vagy egy pr-érték, például egy névtelen ideiglenes (C++17-ig)), és a copy konstruktort választja, ha az argumentum egy l-érték (megnevezett objektum vagy egy l-értékreferenciát visszaadó függvény/operátor). Ha csak a másoló konstruktor van megadva, akkor minden argumentumkategória azt választja ki (amennyiben const-referenciát vesz fel, mivel az rvalue-k const-referenciákhoz is tudnak kötődni), ami a másolást a mozgatás tartalékává teszi, ha a mozgatás nem elérhető.

A konstruktort “mozgatás-konstruktornak” nevezzük, ha paraméterként rvalue-referenciát vesz fel. Nem köteles mozgatni semmit, az osztálynak nem kell, hogy legyen mozgatandó erőforrása, és egy ‘move konstruktor’ nem biztos, hogy képes mozgatni egy erőforrást, mint abban a megengedhető (de talán nem értelmes) esetben, amikor a paraméter egy const rvalue referencia (const T&&).

Példa

Futtassa ezt a kódot
#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);}

Kimenet:

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

Hibajelentések

A következő, a viselkedést megváltoztató hibajelentéseket visszamenőleg alkalmazták a korábban közzétett C++ szabványokra.

DR Applied to Behavior as published Correct behavior
CWG 1402 C++11 egy alapértelmezett move konstruktort töröltek, amely
egy nem triviális másoló konstruktort hívna;
egy alapértelmezett mozdulat-konstruktor, amelyet töröltek
még mindig részt vett a túlterhelés feloldásában
lehetővé teszi az ilyen másolatkonstruktor hívását;
nem vették figyelembe a túlterhelés felbontásban
CWG 2094 C++11 egy alapértelmezett
move konstruktorból készült illékony alobjektum nem.triviális (CWG496)
triviális nem érintett

Lásd még

  • konvertáló konstruktor
  • másolás hozzárendelés
  • másoló konstruktor.
  • másolás elision
  • alapértelmezett konstruktor
  • destruktor
  • explicit
  • inicializálás
    • aggregált inicializálás
    • . konstans inicializálás
    • másolás inicializálás
    • alapértelmezett inicializálás
    • közvetlen inicializálás
    • inicializáló lista
    • lista inicializálás
    • referencia inicializálás
    • érték inicializálás
    • nulla inicializálás
  • mozgatás hozzárendelés
  • new

Vélemény, hozzászólás? Kilépés a válaszból

Az e-mail-címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük

Legutóbbi bejegyzések

  • Az Acela visszatért: New York vagy Boston 99 dollárért
  • OMIM bejegyzés – # 608363 – CHROMOSOME 22q11.2 DUPLICATION SYNDROME
  • Kate Albrecht szülei – Tudj meg többet apjáról Chris Albrechtről és anyjáról Annie Albrechtről
  • Temple Fork Outfitters
  • Burr (regény)

Archívum

  • 2022 február
  • 2022 január
  • 2021 december
  • 2021 november
  • 2021 október
  • 2021 szeptember
  • 2021 augusztus
  • 2021 július
  • 2021 június
  • 2021 május
  • 2021 április
  • 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