3 votes

Constructeur de déplacement et affectation de déplacement

J'ai lu le livre "The C++ programing language 4th edition" de Bjarne Stroustrup (le créateur de c++) et j'ai appris à connaître les constructeurs et les affectations de déplacement.

Dans le livre de la classe vector (voir 1 pour l'en-tête ci-dessous), il montre comment implémenter le constructeur de déplacement (voir 2 ci-dessous) et dit que l'affectation de déplacement est implémentée de manière similaire, mais ne montre pas comment. J'ai moi-même implémenté l'affectation de déplacement (voir 3 ci-dessous) et tout semble fonctionner correctement, mais je ne suis pas sûr de l'avoir fait correctement.

Je n'obtiens aucune erreur et j'ai regardé de nombreux exemples mais je ne peux pas confirmer que c'est correct pour ma classe spécifique. Quelqu'un d'expérimenté en C++ peut-il regarder mon code et me dire s'il est correct ?

EDIT : Veuillez également consulter le point 4 pour les constructeurs et les destructeurs.

Merci pour votre temps.

P.S. : Tous les conseils ou modifications utiles sont les bienvenus.

1) Fichier d'en-tête de classe :

#ifndef VECTOR_H
#define VECTOR_H

#include <cstdlib>
#include <iostream>
#include <stdexcept>

using namespace std;

template<typename T>
class Vector {

public:
    // constructors
    Vector(int s);
    Vector(std::initializer_list<T>);

    // destructor
    ~Vector();

    // copy constructor and copy assignment
    Vector(Vector&);
    Vector<T>& operator=(Vector&);

    // move constructor and move assignment
    Vector(Vector&&);
    Vector<T>& operator=(Vector&&);

    // operators
    T& operator[](int);
    const T& operator[](int) const; // the second const means that this function cannot change the state of the class
                                    // we define operator[] the second time for vectors containing constant members;
    // accessors
    int getSize();

private:
    int size;
    T* elements;

};

#endif /* VECTOR_H */

2) Constructeur de mouvement (implémenté de la même manière que le livre) :

// move constructor 
template<typename T>
Vector<T>::Vector(Vector&& moveme) : size{moveme.size}, elements{moveme.elements}
{
    moveme.elements = nullptr;
    moveme.size = 0;
}

3) Déplacement de l'affectation (pas sûr que ce soit correct) :

// move assignment
template<typename T>
Vector<T>& Vector<T>::operator=(Vector&& moveme) 
{
    delete[] elements; // delete old values
    elements = moveme.elements;
    size = moveme.size;
    moveme.elements = nullptr;
    moveme.size = 0;
    return *this;
}

4) Constructeurs et destructeurs :

#include <array>

#include "Vector.h"

// constructors
template<typename T>
Vector<T>::Vector(int s) {    
    if(s<0) throw length_error{"Vector::Vector(int s)"};
    // TODO: use Negative_size{} after learning how to write custom exceptions
    this->size = s;
    this->elements = new T[s];
}

template<typename T>
Vector<T>::Vector(std::initializer_list<T> list) : size(list.size()), 
        elements(new T[list.size()]) 
{
    copy(list.begin(), list.end(), elements);
}

// destructor
template<typename T>
Vector<T>::~Vector()
{
    delete[] this->elements;
}

1voto

hammeramr Points 150

Puisque cette question a fait l'objet d'une réponse dans les commentaires, j'ai pensé suivre les conseils de la méta : Question sans réponse, mais problème résolu dans les commentaires (ou développé dans le chat) et rédiger un court Wiki communautaire pour conclure et répondre à la question.

J'ajouterai également des informations et des conseils supplémentaires utiles provenant d'autres utilisateurs qui ont rejoint la discussion dans les commentaires.

Bo Presson répondre et fournir des informations supplémentaires sur le placement des modèles :

L'affectation des déplacements semble raisonnable, sauf que le fait de placer les modèles dans un fichier cpp les rend utilisables uniquement dans ce fichier cpp. un fichier cpp les rend utilisables uniquement dans ce fichier cpp. Voir Pourquoi les modèles ne peuvent-ils être mis en œuvre que dans le fichier d'en-tête ?

Rakete1111 en clarifiant un malentendu que j'avais concernant la sémantique des mouvements :

std::move != sémantique du déplacement. Vous avez la sémantique move, où les valeurs r peuvent être déplacées (en utilisant le constructeur move) au lieu d'être copiées. std::move est juste un moyen d'activer la sémantique du déplacement (comme l'utilisation du constructeur move ) pour des types qui ne sont pas des rvalues.

kim366 en soulevant la question de l'optimisation du retour avec Jive Dadson et je réponds :

... Aussi, n'y a-t-il pas vraiment d'optimisation des valeurs de retour, si vous n'avez pas ont surchargé déplacer ctors/assignments ? -kim366

Il semble que oui, dans l'exemple (voir fonction ci-dessous) il dit que z = x + y + z copiera le résultat de retour deux fois "Si un vecteur est grand, disons, 10 000 doubles, cela pourrait être embarrassant." Mais "Compte tenu de cette définition, le compilateur choisira le constructeur move pour implémenter le transfert de la valeur de retour..." Il a inventé le C++ donc je vais juste le croire sa parole :). Vector operator+(const Vector& a, const Vector& b) { if (a.size()!=b.size()) throw Vector_size_mismatch{}; Vector res(a.size()); for (int i=0; i!=a.size(); ++i) res[i]=a[i]+b[i]; return res; } - hammeramr

(L'exemple est tiré du livre : "Le langage de programmation C++ 4ème édition" par Bjarne Stroustrup )

Voir aussi Qu'est-ce que l'idiome "copier et échanger" ? -Jive Dadson

J'espère que les gens trouveront cela utile et merci à ceux qui ont participé.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X