Skip to content
Menu
CDhistory
CDhistory

Costruttori move

Posted on Maggio 26, 2021 by admin

Un costruttore move di classe T è un costruttore non-template il cui primo parametro è T&&, const T&&, volatile T&&, o const volatile T&&, e non ci sono altri parametri, o il resto dei parametri ha tutti valori predefiniti.

  • Contenuti
  • Sintassi
  • Spiegazione
  • Costruttore di mosse implicitamente dichiarato
  • Cancellato costruttore di mosse dichiarato implicitamente
  • Costruttore di move banale
  • Costruttore di spostamento ammissibile
  • Costruttore di mossa implicitamente definito
  • Note
  • Esempio
  • Segnalazioni di difetti
  • Vedi anche

Contenuti

  • 1 Sintassi
  • 2 Spiegazione
  • 3 Costruttore di move implicitamente dichiarato
  • 4 Costruttore di move implicitamente dichiarato cancellato
  • 5 Costruttore di move banale
  • 6 Costruttore di move ammissibile
  • 7 Costruttore di move implicitamentedefinito implicitamente
  • 8 Note
  • 9 Esempio
  • 10 Segnalazioni di difetti
  • 11 Vedi anche

Sintassi

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

Dove class_name deve nominare la classe corrente (o l’istanza corrente di un modello di classe), o, quando è dichiarato nello spazio dei nomi o in una dichiarazione amica, deve essere un nome di classe qualificato.

Spiegazione

1) Dichiarazione tipica di un costruttore di spostamento.
2) Forzare un costruttore di spostamento ad essere generato dal compilatore.
3) Evitare il costruttore di spostamento implicito.

Il costruttore move è tipicamente chiamato quando un oggetto è inizializzato (tramite inizializzazione diretta o copia-inizializzazione) da rvalue (xvalue o prvalue) (fino al C++17)xvalue (dal C++17) dello stesso tipo, inclusa

  • inizializzazione: T a = std::move(b); o T a(std::move(b));, dove b è di tipo T;
  • passaggio di argomento di funzione: f(std::move(a));, dove a è di tipo T e f è void f(T t);
  • ritorno di funzione: return a; dentro una funzione come T f(), dove a è di tipo T che ha un costruttore move.

Quando l’inizializzatore è un valore pr, la chiamata al costruttore move è spesso ottimizzata (fino al C++17) e mai fatta (dal C++17), vedi copy elision.

I costruttori move tipicamente “rubano” le risorse detenute dall’argomento (es.) piuttosto che farne delle copie, e lasciano l’argomento in qualche stato valido ma altrimenti indeterminato. Per esempio, spostarsi da una std::string o da uno std::vector può risultare nel lasciare l’argomento vuoto. Tuttavia, non si dovrebbe fare affidamento su questo comportamento. Per alcuni tipi, come std::unique_ptr, lo stato “moved-from” è completamente specificato.

Costruttore di mosse implicitamente dichiarato

Se non vengono forniti costruttori di mosse definiti dall’utente per un tipo di classe (struct, class, o union), e tutto ciò che segue è vero:

  • non ci sono costruttori di copia dichiarati dall’utente;
  • non ci sono operatori di assegnazione di copia dichiarati dall’utente;
  • non ci sono operatori di assegnazione di spostamento dichiarati dall’utente;
  • non c’è un distruttore dichiarato dall’utente.

allora il compilatore dichiarerà un costruttore move come un membro non esplicito inline public della sua classe con la firma T::T(T&&).

Una classe può avere più costruttori di mosse, per esempio sia T::T(const T&&) che T::T(T&&). Se alcuni costruttori di mosse definiti dall’utente sono presenti, l’utente può ancora forzare la generazione del costruttore di mosse implicitamente dichiarato con la parola chiave default.

Il costruttore di mosse dichiarato implicitamente (o predefinito alla sua prima dichiarazione) ha una specifica di eccezione come descritto nella specifica di eccezione dinamica (fino a C++17)specifica di eccezione (da C++17)

Cancellato costruttore di mosse dichiarato implicitamente

Il costruttore di mosse dichiarato implicitamente o predefinito per la classe T è definito come cancellato se una delle seguenti è vera:

  • T ha membri di dati non statici che non possono essere spostati (hanno costruttori di spostamento cancellati, inaccessibili o ambigui);
  • T ha classe base diretta o virtuale che non può essere spostata (ha costruttori di spostamento cancellati, inaccessibili o ambigui);
  • T ha una classe base diretta o virtuale con un distruttore cancellato o inaccessibile;
  • T è una classe simile all’unione e ha un membro variante con un costruttore di spostamento non banale.

Un costruttore move predefinito che viene cancellato viene ignorato dalla risoluzione dei sovraccarichi (altrimenti impedirebbe la copia-inizializzazione da rvalue).

Costruttore di move banale

Il costruttore di move per la classe T è banale se tutto ciò che segue è vero:

  • non è fornito dall’utente (cioè, è implicitamente definito o predefinito);
  • T non ha funzioni membro virtuali;
  • T non ha classi base virtuali;
  • il costruttore di mosse selezionato per ogni base diretta di T è banale;
  • il costruttore di mosse selezionato per ogni membro non statico di tipo classe (o array di tipo classe) di T è banale.

Un costruttore di move banale è un costruttore che esegue la stessa azione del costruttore di copia banale, cioè fa una copia della rappresentazione dell’oggetto come per std::memmove. Tutti i tipi di dati compatibili con il linguaggio C (tipi POD) sono banalmente spostabili.

Costruttore di spostamento ammissibile

Un costruttore di spostamento è ammissibile se non è cancellato.

(fino al C++20)

Un costruttore di mosse è ammissibile se

  • non è cancellato, e
  • i suoi vincoli associati, se presenti, sono soddisfatti, e
  • nessun costruttore di mosse con lo stesso tipo di primo parametro è più vincolato di esso.
(dal C++20)

La trivialità dei costruttori di mosse ammissibili determina se la classe è un tipo a vita implicita, e se la classe è un tipo banalmente copiabile.

Costruttore di mossa implicitamente definito

Se il costruttore di mossa implicitamente dichiarato non è né cancellato né banale, è definito (cioè, viene generato e compilato un corpo di funzione) dal compilatore se odr-usato o necessario per la valutazione di una costante. Per i tipi unionali, il costruttore di move implicitamente definito copia la rappresentazione dell’oggetto (come da std::memmove). Per i tipi di classe non unionali (class e struct), il costruttore move esegue lo spostamento completo dei membri delle basi e dei membri non statici dell’oggetto, nel loro ordine di inizializzazione, usando l’inizializzazione diretta con un argomento xvalue. Se questo soddisfa i requisiti di un costruttore constexpr, il costruttore move generato è constexpr.

Note

Per rendere possibile la garanzia di eccezione forte, i costruttori move definiti dall’utente non dovrebbero lanciare eccezioni. Per esempio, std::vector si basa su std::move_if_noexcept per scegliere tra move e copy quando gli elementi devono essere riposizionati.

Se sono forniti entrambi i costruttori copy e move e nessun altro costruttore è praticabile, la risoluzione dei sovraccarichi seleziona il costruttore move se l’argomento è un rvalore dello stesso tipo (un xvalore come il risultato di std::move o un prvalore come un temporaneo senza nome (fino al C++17)), e seleziona il costruttore copy se l’argomento è un lvalue (un oggetto con nome o una funzione/operatore che restituisce un riferimento a lvalue). Se viene fornito solo il costruttore di copia, tutte le categorie di argomenti lo selezionano (finché prende un riferimento a const, poiché gli rvalori possono legarsi a riferimenti const), il che rende la copia il fallback per lo spostamento, quando lo spostamento non è disponibile.

Un costruttore è chiamato un ‘costruttore di spostamento’ quando prende un riferimento rvalue come parametro. Non è obbligato a spostare nulla, la classe non è obbligata ad avere una risorsa da spostare e un ‘costruttore di spostamento’ potrebbe non essere in grado di spostare una risorsa come nel caso ammissibile (ma forse non sensato) in cui il parametro è un riferimento rvalue const (const T&&).

Esempio

Esegui questo codice
#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

Segnalazioni di difetti

Le seguenti segnalazioni di difetti che cambiano il comportamento sono state applicate retroattivamente agli standard C++ precedentemente pubblicati.

DR Applicato a Comportamento come pubblicato Comportamento corretto
CWG 1402 C++11 un costruttore di movimento predefinito che avrebbe
chiamato un costruttore di copia non banale è stato eliminato;
un costruttore di mosse predefinito che è stato eliminato
ha comunque partecipato alla risoluzione dei sovraccarichi
consente la chiamata a tale costruttore di copie;
fatta ignorare nella risoluzione degli overload
CWG 2094 C++11 un sottooggetto volatile fatto di un costruttore di move predefinito
nonbanale (CWG496)
la banalità non è interessata

Vedi anche

  • costruttore di conversione
  • assegnazione di copia
  • costruttore di copia
  • elisione di copia
  • costruttore predefinito
  • distruttore
  • esplicito
  • inizializzazione
    • inizializzazione aggregata
    • inizializzazione costante
    • inizializzazione di copia
    • inizializzazione predefinita
    • inizializzazione diretta
    • inizializzatore lista
    • inizializzazione lista
    • inizializzazione riferimento
    • inizializzazione valore
    • inizializzazione zero
  • assegnazione spostamento
  • nuovo

Lascia un commento Annulla risposta

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Articoli recenti

  • Acela è tornato: NYC o Boston per $99
  • I genitori di Kate Albrecht – Per saperne di più sul padre Chris Albrecht e la madre Annie Albrecht
  • Temple Fork Outfitters
  • Burr (romanzo)
  • Trek Madone SLR 9 Disc

Archivi

  • Febbraio 2022
  • Gennaio 2022
  • Dicembre 2021
  • Novembre 2021
  • Ottobre 2021
  • Settembre 2021
  • Agosto 2021
  • Luglio 2021
  • Giugno 2021
  • Maggio 2021
  • Aprile 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