Skip to content
Menu
CDhistory
CDhistory

Constructorii de mutare

Posted on mai 26, 2021 by admin

Un constructor de mutare al clasei T este un constructor non-template al cărui prim parametru este T&&, const T&&, volatile T&& sau const volatile T&& și fie nu există alți parametri, fie restul parametrilor au toți valori implicite.

  • Contenit
  • Sintaxa
  • Explicație
  • Constructor de mutare declarat implicit
  • Constructor de mutare implicit declarat șters
  • Constructorul de mutare trivial
  • Constructor de mutare eligibil
  • Constructor de mutare definit implicit
  • Note
  • Exemplu
  • Rapoarte de defecte
  • Vezi și

Contenit

  • 1 Sintaxa
  • 2 Explicație
  • 3 Constructor de mutare declarat implicit
  • 4 Constructor de mutare implicit eliminat
  • 5 Constructor de mutare trivial
  • 6 Constructor de mutare eligibil
  • 7 Constructor de mutare implicit
  • 7 Constructor de mutare implicit.defined move constructor
  • 8 Note
  • 9 Exemplu
  • 10 Rapoarte de defecte
  • 11 Vezi și

Sintaxa

class_name ( class_name && ) (1) (din C++11)
class_name ( class_name && ) = implicit; (2) (din C++11)
class_name ( class_name && ) = delete; (3) (din C++11)

În care nume_clasă trebuie să numească clasa curentă (sau instanțierea curentă a unui șablon de clasă) sau, atunci când este declarată la nivelul spațiului de nume sau într-o declarație friend, trebuie să fie un nume de clasă calificat.

Explicație

1) Declararea tipică a unui constructor de mutare.
2) Forțarea unui constructor de mutare să fie generat de compilator.
3) Evitarea constructorului de mutare implicit.

Constructorul de mutare este de obicei apelat atunci când un obiect este inițializat (prin inițializare directă sau inițializare prin copiere) din rvaloare (xvaloare sau prvaloare) (până în C++17)xvaloare (din C++17) de același tip, inclusiv

  • inițializare: T a = std::move(b); sau T a(std::move(b));, unde b este de tip T;
  • trecerea argumentelor funcției: f(std::move(a));;, unde a este de tip T și f este void f(T t);
  • funcția return: return a; în interiorul unei funcții cum ar fi T f(), unde a este de tip T care are un constructor move.

Când inițializatorul este o prvaloare, apelul constructorului de mutare este adesea optimizat (până în C++17)nu se face niciodată (din C++17), vezi eliziune de copiere.

Constructorii de mutare „fură” de obicei resursele deținute de argument (de ex.g. pointeri la obiecte alocate dinamic, descriptori de fișiere, socket-uri TCP, fluxuri I/O, fire de execuție etc.) mai degrabă decât să facă copii ale acestora, și lasă argumentul într-o stare validă, dar altfel nedeterminată. De exemplu, trecerea de la un std::string sau de la un std::vector poate duce la lăsarea argumentului gol. Cu toate acestea, nu trebuie să vă bazați pe acest comportament. Pentru unele tipuri, cum ar fi std::unique_ptr, starea „moved-from” este complet specificată.

Constructor de mutare declarat implicit

Dacă nu sunt prevăzuți constructori de mutare definiți de utilizator pentru un tip de clasă (struct, class sau union) și toate următoarele sunt adevărate:

  • nu există constructori de copiere declarați de utilizator;
  • nu există operatori de atribuire de copiere declarați de utilizator;
  • nu există operatori de atribuire de mutare declarați de utilizator;
  • nu există un destructor declarat de utilizator.

atunci compilatorul va declara un constructor de mutare ca membru neexplicit inline public al clasei sale cu semnătura T::T(T&&).

O clasă poate avea mai mulți constructori de mutare, de exemplu, atât T::T(const T&&), cât și T::T(T&&). În cazul în care există constructori de mutare definiți de utilizator, utilizatorul poate totuși să forțeze generarea constructorului de mutare implicit declarat cu ajutorul cuvântului cheie default.

Constructorul de mutare declarat implicit (sau implicit la prima sa declarare) are o specificație de excepție așa cum este descrisă în specificația de excepție dinamică (până în C++17)specificația de excepție (din C++17)

Constructor de mutare implicit declarat șters

Constructorul de mutare implicit declarat sau implicit pentru clasa T este definit ca fiind șters dacă oricare dintre următoarele este adevărat:

  • T are membri de date non-statice care nu pot fi mutați (au constructori de mutare șterși, inaccesibili sau ambigui);
  • T are o clasă de bază directă sau virtuală care nu poate fi mutată (are constructori de mutare șterși, inaccesibili sau ambigui);
  • T are o clasă de bază directă sau virtuală cu un destructor șters sau inaccesibil;
  • T este o clasă de tip uniune și are un membru variant cu un constructor de mutare netrivial.

Un constructor de mutare predefinit care este eliminat este ignorat de rezoluția supraîncărcării (altfel ar împiedica inițializarea prin copiere din rvaloare).

Constructorul de mutare trivial

Constructorul de mutare pentru clasa T este trivial dacă toate elementele următoare sunt adevărate:

  • nu este furnizat de utilizator (ceea ce înseamnă că este definit implicit sau implicit);
  • T nu are funcții membre virtuale;
  • T nu are clase de bază virtuale;
  • constructorul de mutare selectat pentru fiecare bază directă a lui T este trivial;
  • constructorul de mutare selectat pentru fiecare tip de clasă non-statică (sau matrice de tip de clasă) membru al lui T este trivial.

Un constructor trivial de mutare este un constructor care efectuează aceeași acțiune ca și constructorul trivial de copiere, adică realizează o copie a reprezentării obiectului ca și cum ar fi făcut-o prin std::memmove. Toate tipurile de date compatibile cu limbajul C (tipuri POD) sunt mutabile trivial.

Constructor de mutare eligibil

Un constructor de mutare este eligibil dacă nu este șters.

(până la C++20)

Un constructor de mutare este eligibil dacă

  • nu este șters și
  • constrângerile sale asociate, dacă există, sunt satisfăcute și
  • niciun constructor de mutare cu același tip de prim parametru nu este mai constrâns decât el.
(din C++20)

Trivialitatea constructorilor de mutare eligibili determină dacă clasa este un tip cu durată de viață implicită și dacă clasa este un tip copiabil în mod trivial.

Constructor de mutare definit implicit

Dacă constructorul de mutare declarat implicit nu este nici eliminat, nici trivial, acesta este definit (adică se generează și se compilează un corp de funcție) de compilator dacă este odr-utilizat sau este necesar pentru evaluarea constantelor. Pentru tipurile de uniune, constructorul de mutare implicit-definit copiază reprezentarea obiectului (ca prin std::memmove). Pentru tipurile de clasă non-union (class și struct), constructorul move efectuează mutarea completă a bazelor și a membrilor non-statici ai obiectului, în ordinea inițializării lor, utilizând inițializarea directă cu un argument xvalue. Dacă acest lucru satisface cerințele unui constructor constexpr, constructorul de mutare generat este constexpr.

Note

Pentru a face posibilă garantarea excepțiilor puternice, constructorii de mutare definiți de utilizator nu trebuie să arunce excepții. De exemplu, std::vector se bazează pe std::move_if_noexcept pentru a alege între move și copy atunci când elementele trebuie să fie relocate.

Dacă sunt furnizați atât constructorii copy cât și move și niciun alt constructor nu este viabil, rezoluția supraîncărcărilor selectează constructorul move dacă argumentul este o valoare r de același tip (o valoare x, cum ar fi rezultatul std::move sau o valoare pr, cum ar fi o valoare temporară fără nume (până în C++17)) și selectează constructorul copy dacă argumentul este o valoare l (un obiect cu nume sau o funcție/operator care returnează o referință la o valoare l). Dacă este furnizat doar constructorul de copiere, toate categoriile de argumente îl selectează (atâta timp cât acceptă o referință la const, deoarece rvalorile se pot lega la referințe const), ceea ce face din copiere soluția de rezervă pentru mutare, atunci când mutarea nu este disponibilă.

Un constructor se numește „constructor de mutare” atunci când acceptă ca parametru o referință la rvaloare. Nu este obligat să mute nimic, nu este necesar ca clasa să aibă o resursă care să fie mutată, iar un ‘constructor de mutare’ poate să nu fie capabil să mute o resursă ca în cazul permis (dar poate nu sensibil) în care parametrul este o referință const rvalue (const T&&).

Exemplu

Executați acest cod
#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);}

Scoatere:

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

Rapoarte de defecte

Celelalte rapoarte de defecte care schimbă comportamentul au fost aplicate retroactiv la standardele C++ publicate anterior.

DR Aplicat la Comportamentul așa cum a fost publicat Comportamentul corect
CWG 1402 C++11 a fost eliminat un constructor de mutare implicită care ar
apela un constructor de copiere non-trivial;
un constructor de mutare prestabilit care este eliminat
a participat totuși la rezolvarea supraîncărcării
permite apelarea unui astfel de constructor de copiere;
a fost ignorat în rezolvarea suprasarcinilor
CWG 2094 C++11 un subobiect volatil făcut dintr-un constructor de mișcare defect
move constructor nontrivial (CWG496)
trivialitatea nu este afectată

Vezi și

  • constructor de conversie
  • copy assignment
  • constructor de copiere
  • copy constructor
  • eliziune copie
  • constructor implicit
  • destructor
  • explicit
  • inițializare
    • inițializare agregată
    • . inițializare constantă
    • inițializare copie
    • inițializare implicită
    • inițializare directă
    • inițializator listă
    • inițializare listă
    • inițializare referință
    • inițializare valoare
    • inițializare zero
  • mutare atribuire
  • nou

Lasă un răspuns Anulează răspunsul

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *

Articole recente

  • Acela s-a întors: NYC sau Boston pentru 99 de dolari
  • Părinții lui Kate Albrecht – Aflați mai multe despre tatăl ei, Chris Albrecht, și despre mama ei, Annie Albrecht
  • Temple Fork Outfitters
  • Burr (roman)
  • Trek Madone SLR 9 Disc

Arhive

  • februarie 2022
  • ianuarie 2022
  • decembrie 2021
  • noiembrie 2021
  • octombrie 2021
  • septembrie 2021
  • august 2021
  • iulie 2021
  • iunie 2021
  • mai 2021
  • aprilie 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