Partage
  • Partager sur Facebook
  • Partager sur Twitter

Tentative de référencement d'une fonction supprimé

Sujet résolu
    5 juin 2020 à 19:19:56

    Bonjour, pour m’entraîner je fais l'exercice sur le javaquarium, j'ai donc créer une classe Aquarium avec comme attribut un vector d'unique_ptr afin de pouvoir y stocker mes poissons j'ai donc aussi une methodes 'AjouterPoisson' mais je rencontre un problème: j'ai comme erreur "tentative de référencement d'une fonction supprimé" quelques soit la façon: que ça soit par référence ou par mouvement
    void Aquarium::ajouterPoisson(std::unique_ptr<Poisson>& Poissons) {
    	m_Poissons.push_back(std::move(Poissons));
    }
    
    void Aquarium::ajouterPoisson(std::unique_ptr<Poisson>&& Poissons) {
    	m_Poissons.push_back(std::move(Poissons));
    }
    ---------
    auto poisson = std::make_unique<Poisson>("Gerard"s,Sexe::Male);
    aquarium.ajouterPoisson(poisson);

    je suis tombé sur ce topic en cherchant le problème: 
    https://openclassrooms.com/forum/sujet/passage-par-reference-d-un-unique-ptr
    M
    ais les façons énoncé ne marche pour moi (je n'ai pas essayer les shared_ptr comme dit par l'auteur du topic parce que je trouve ça inapproprié )

    J'aimerai donc savoir comment régler le soucis.

    Merci

    -
    Edité par Kiwi_Dch 5 juin 2020 à 19:21:18

    • Partager sur Facebook
    • Partager sur Twitter
      5 juin 2020 à 20:42:28

      Salut

      Déjà, pourrais tu nous donner un peu plus de code (un genre de code minimum compilable qui puisse reproduire le problème), et nous indiquer l'erreur exacte que tu obtiens lors de la compilation.

      Cela nous facilitera énormément la tâche pour te répondre ;)

      Ensuite, pourquoi veux tu créer un poisson (ou n'importe quoi d'autre) avant de le transmettre à la fonction de ta classe qui permettra de le sauvegarder?

      Poses toi peut-être la question suivante:

      Si, pour une raison ou une autre -- disons: parce que la population de l'aquarium est déjà trop importante -- l'aquarium refuse d'ajouter le poisson, y a-t-il vraiment du sens à vouloir garder le poisson qui a (déjà été créé mais qui a) été refusé par l'aquarium?

      Si oui, que compte tu en faire?

      Ensuite, pose toi peut-être une deuxième question

      Y a-t-il la moindre différence -- au niveau de l'aquarium -- entre le fait d'ajouter un poisson et celui de rajouter une algue dans l'aquarium?

      Tu te rendras sans doute compte qu'en fait, il s'agit toujours... d'y rajouter un élément, et que la logique à mettre en place reste la même

      Enfin, poses-toi une troisième question, la plus importante:

      Est-ce vraiment à l'utilisateur de l'aquarium de prendre la responsabilité de créer le poisson (ou l'algue) qu'il veut mettre dedans?

      Et là, tu te rappelleras (ou tu apprendras peut-être en lisant cette réponse) que l'utilisateur est un imbécile distrait qui n'attend que l'occasion de faire une connerie et que, par conséquent, tu ne dois en aucun cas lui donner ce genre de responsabilité.

      Après avoir murement réfléchi à la manière de faire pour permettre à l'utilisateur d'ajouter un élément (poisson ou algue) à l'aquarium tout en évitant de lui donner la responsabilité de créer cet élément, tu en viendra sans doute à la conclusion que, la création de l'élément souhaité doit se faire au niveau de la fonction qui permet d'ajouter le nouvel élément à l'aquarium, et que l'utilisateur ne doit savoir que... le type d'élément qu'il veut ajouter.

      Tu devrais donc en arriver à la conclusion que tu as besoin d'une notion permettant de distinguer les algues des poissons, comme une énumération qui prendrait la forme de

      enum ElementType{
          SeaWeed,
          Fish
      };

      et que c'est à la fonction de récolter l'ensemble des informations permettant de créer l'élément (en vérifiant leur cohérence) avant de faire appel à une fabrique d'éléments, sous une forme proche de

      void Aquarium::ajouter(ElementType t, std::string const & name = ""){
          /* seuls les poissons ont un nom, le nom n'a aucun 
           * sens pour les algues
           */
          assert(t== Fish || (t==SeaWeed && name=="") &&
                 "only fishes can be named");
          auto elem = Factory::create(t, name);
          /* il faudra l'ajouter correctement ici */
      }
      • Partager sur Facebook
      • Partager sur Twitter
      Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
        5 juin 2020 à 21:35:56

        koala01 a écrit:

        Salut

        Déjà, pourrais tu nous donner un peu plus de code (un genre de code minimum compilable qui puisse reproduire le problème), et nous indiquer l'erreur exacte que tu obtiens lors de la compilation.

        Cela nous facilitera énormément la tâche pour te répondre ;)

        Ensuite, pourquoi veux tu créer un poisson (ou n'importe quoi d'autre) avant de le transmettre à la fonction de ta classe qui permettra de le sauvegarder?

        Poses toi peut-être la question suivante:

        Si, pour une raison ou une autre -- disons: parce que la population de l'aquarium est déjà trop importante -- l'aquarium refuse d'ajouter le poisson, y a-t-il vraiment du sens à vouloir garder le poisson qui a (déjà été créé mais qui a) été refusé par l'aquarium?

        Si oui, que compte tu en faire?

        Ensuite, pose toi peut-être une deuxième question

        Y a-t-il la moindre différence -- au niveau de l'aquarium -- entre le fait d'ajouter un poisson et celui de rajouter une algue dans l'aquarium?

        Tu te rendras sans doute compte qu'en fait, il s'agit toujours... d'y rajouter un élément, et que la logique à mettre en place reste la même

        Enfin, poses-toi une troisième question, la plus importante:

        Est-ce vraiment à l'utilisateur de l'aquarium de prendre la responsabilité de créer le poisson (ou l'algue) qu'il veut mettre dedans?

        Et là, tu te rappelleras (ou tu apprendras peut-être en lisant cette réponse) que l'utilisateur est un imbécile distrait qui n'attend que l'occasion de faire une connerie et que, par conséquent, tu ne dois en aucun cas lui donner ce genre de responsabilité.

        Après avoir murement réfléchi à la manière de faire pour permettre à l'utilisateur d'ajouter un élément (poisson ou algue) à l'aquarium tout en évitant de lui donner la responsabilité de créer cet élément, tu en viendra sans doute à la conclusion que, la création de l'élément souhaité doit se faire au niveau de la fonction qui permet d'ajouter le nouvel élément à l'aquarium, et que l'utilisateur ne doit savoir que... le type d'élément qu'il veut ajouter.

        Tu devrais donc en arriver à la conclusion que tu as besoin d'une notion permettant de distinguer les algues des poissons, comme une énumération qui prendrait la forme de

        enum ElementType{
            SeaWeed,
            Fish
        };

        et que c'est à la fonction de récolter l'ensemble des informations permettant de créer l'élément (en vérifiant leur cohérence) avant de faire appel à une fabrique d'éléments, sous une forme proche de

        void Aquarium::ajouter(ElementType t, std::string const & name = ""){
            /* seuls les poissons ont un nom, le nom n'a aucun 
             * sens pour les algues
             */
            assert(t== Fish || (t==SeaWeed && name=="") &&
                   "only fishes can be named");
            auto elem = Factory::create(t, name);
            /* il faudra l'ajouter correctement ici */
        }

        Merci de venir a mon secours
        Je peux donner l’entièreté de mon code(il n'est pas très long je vient a peine de le commencer et j'avais pour but de juste commencé a faire l'aquarium et les poissons) mais compilable non vu que j'ai cette erreur:

        #include <iostream>
        #include "Aquarium.h"
        
        int main()
        {
           std::vector<std::unique_ptr<Poisson>> poissons{ std::make_unique<Poisson>("Theo"s,Sexe::Male),std::make_unique<Poisson>("Marine"s,Sexe::Femelle) };
            Aquarium aquarium(poissons);
            auto poisson = std::make_unique<Poisson>("Gerard"s, Sexe::Male);
            aquarium.ajouterPoisson(poisson);
            aquarium.PasserTour();
        
            return 0;
        }
        
        
        #ifndef  POISSON_H
        #define POISSON_H
        
        #include <string>
        #include <cassert>
        #include <iostream>
        
        using namespace std::literals;
        
        enum class Sexe {
        	Male,
        	Femelle
        };
        
        class Poisson
        {
        public:
        	Poisson() = delete;
        	Poisson(std::string const& nom, Sexe const sexe);
        
        	friend void AfficherCaracteristique(Poisson const& poisson) noexcept;
        
        	Poisson(Poisson const& poisson) = delete;
        	Poisson& operator=(Poisson const& poisson) = delete;
        	Poisson(Poisson&& poisson) = delete;
        	Poisson& operator=(Poisson&& poisson) = delete;
        private:
        
        	std::string m_nom;
        	Sexe m_sexe;
        };
        
        
        #endif // ! POISSON_H
        #include "Poisson.h"
        
        
        Poisson::Poisson(std::string const& nom, Sexe const sexe):m_nom(nom),m_sexe(sexe) {
        	assert(!std::empty(nom) && "Le nom ne doit pas etre vide");
        	assert(sexe == Sexe::Femelle || m_sexe == Sexe::Male && "Le sexe doit etre valide");
        
        }
        
        void AfficherCaracteristique(Poisson const& poisson) noexcept {
        	std::string strSexe{};
        	if (poisson.m_sexe == Sexe::Femelle) {
        		strSexe = "Femelle"s;
        	}
        	else {
        		strSexe = "Male"s;
        	}
        	std::cout << "Nom: "s << poisson.m_nom << " Sexe: " << strSexe << std::endl;
        
        }
        #ifndef AQUARIUM_H
        #define AQUARIUM_H
        
        #include "Poisson.h"
        
        #include <memory>
        #include <vector>
        #include <cassert>
        #include <iostream>
        
        class Aquarium
        {
        public:
        	Aquarium() = delete;
        	Aquarium(std::vector<std::unique_ptr<Poisson>>& Poissons);
        
        	void ajouterPoisson(std::unique_ptr<Poisson>& Poissons);
        	void PasserTour();
        
        	Aquarium& operator=(Aquarium const& aquarium) = delete;
        	Aquarium(Aquarium const& aquarium) = delete;
        	Aquarium& operator=(Aquarium&& aquarium) = delete;
        	Aquarium(Aquarium&& aquarium) = delete;
        
        private:
        	std::vector<std::unique_ptr<Poisson>> m_Poissons;
        	int m_tour;
        };
        
        #endif
        #include "Aquarium.h"
        
        
        Aquarium::Aquarium(std::vector<std::unique_ptr<Poisson>>& Poissons) : m_Poissons(std::move(Poissons)){
        	assert(!std::empty(m_Poissons) && "Il doit y avoir des poissons"); // a voir
        	m_tour = 0;
        }
        
        void Aquarium::ajouterPoisson(std::unique_ptr<Poisson>& Poissons) {
        	m_Poissons.push_back(std::move(Poissons));
        }
        
        void Aquarium::PasserTour() {
        	m_tour++;
        
        	std::cout << "Tour: " << m_tour << std::endl;
        	std::cout << "il y a " << m_Poissons.size() << " Poissons dans l'aquarium" << std::endl;
        	for (auto const& p : m_Poissons) {
        		AfficherCaracteristique(*p);
        	}
        }
        Pour la responsabilité je n'ai pas bien compris ce que l'utilisateur peut bien faire comme connerie parce que dans le pire des cas le code ne se compile pas(je pense) mais c'est vrai que votre façon de faire évite de répéter du code et est beaucoup plus pratique.





        • Partager sur Facebook
        • Partager sur Twitter
          5 juin 2020 à 21:40:56

          Salut ! Je commence depuis quelques semaines à comprendre la sémantique de déplacement, et tout le bordel, et ça me fait pas mal galérer... J'ai lu ton post et, comme toi, j'ai pas compris l'erreur à mon premier coup d'oeil. Mais il me semble que tu ne respectes pas le principe de perfect-forwarding, la fonction std::move() prend en paramètre une r-value reference et tu lui passes une l-value reference. D'après le "reference collapsing", une r-value reference de l-value reference donne une l-value reference... Le paramètre passé à std::move n'est pas du bon type. Ce qu'il faudrait serait de caster explicitement ta l-value reference passée à la fonction ajouterPoisser en r-value reference, pour ça, je connais deux technique:

          • Le static_cast typique:
          // [...]
          void foo( bar& lvalue_ref_bar ) {
            std::move( static_cast<bar&&>( lvalue_ref_bar ) );
          }
          • L'utilisation de std::forward, très similaire au cast, dans le comportement:
          #include <utility>
          
          // [...]
          void foo( bar& lvalue_ref_bar ) {
            std::move( std::forward<bar>( lvalue_ref_bar ) );
          }

          Voilà, c'est tout pour moi. Lis bien chaque article de la doc que je t'ai donné, et documente toi le plus possible à ce propos. Etant un débutant, je peux te dire que ce genre de concept bien connu du C++ n'est pas simple à comprendre (foutu langage xD), mais avec pas mal de pratique et de lecture tout se remet dans l'ordre.

          =====

          J'ai fait mes petits tests, mais mon message d'erreur est bien plus explicite que le tien:

          /usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/ext/new_allocator.h:136:23:
          error: call to deleted constructor of 'std::unique_ptr<int, std::default_delete<int> >' { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }

          Mais toujours impossible à comprendre pour un néophyte... C'est une vraie galère le C++. Concrètement j'ai compris le problème grâce à ces notes:

          /home/devio/C++/Random/sources/main.cpp:145:2:
          note: in instantiation of function template specialization 'add_to_list<int>' requested here add_to_list( test ); ^ /usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/unique_ptr.h:397:7:
          note: 'unique_ptr' has been explicitly marked deleted here unique_ptr(const unique_ptr&) = delete;

          Avec la première note on voit que le problème se trouve bien dans la fonction add_to_list. Avec la deuxième note on comprend qu'on essaie de copier un objet qui utilise la sémantique d'entité. C'est à cause de notre std::move dont le paramètre est une l-value reference, je ne sais pas trop ce qui se passe dans la fonction std::move, mais elle semble donner lieu à une copie d'un objet std::unique_ptr alors que ça n'est pas possible.

          -
          Edité par Daimyo_ 5 juin 2020 à 21:55:49

          • Partager sur Facebook
          • Partager sur Twitter
            5 juin 2020 à 21:50:27

            Daimyo_ a écrit:

            Salut ! Je commence depuis quelques semaines à comprendre la sémantique de déplacement, et tout le bordel, et ça me fait pas mal galérer... J'ai lu ton post et, comme toi, j'ai pas compris l'erreur. Mais il me semble que tu ne respectes pas le principe de perfect-forwarding, la fonction std::move() prend en paramètre une r-value reference et tu lui passes une l-value reference. D'après le "reference collapsing", une r-value reference de l-value reference donne une l-value reference... Le paramètre passé à std::move n'est pas du bon type. Ce qu'il faudrait serait de caster explicitement ta l-value reference passée à la fonction ajouterPoisser en r-value reference, pour ça, je connais deux technique:

            • Le static_cast typique:
            // [...]
            void foo( bar& lvalue_ref_bar ) {
              std::move( static_cast<bar&&>( lvalue_ref_bar ) );
            }
            • L'utilisation de std::forward, très similaire au cast, dans le comportement:
            #include <utility>
            
            // [...]
            void foo( bar& lvalue_ref_bar ) {
              std::move( std::forward<bar>( lvalue_ref_bar ) );
            }

            Voilà, c'est tout pour moi. Lis bien chaque article de la doc que je t'ai donné, et documente toi le plus possible à ce propos. Etant un débutant, je peux te dire que ce genre de concept bien connu du C++ n'est pas simple à comprendre (foutu langage xD), mais avec pas mal de pratique et de lecture tout se remet dans l'ordre.

            -
            Edité par Daimyo_ il y a moins de 30s

            Salut merci de m'avoir répondu, moi aussi je viens d'apprendre tout ce concepts dans la semaine, et justement j'ai suivis le cours de zeste de savoir et il semble que std::move() demande a une l-value de se déplacer (je vois ça comme une conversion en r-value)
            https://zestedesavoir.com/contenus/beta/822/la-programmation-en-c-moderne/la-programmation-orientee-objet/la-semantique-de-mouvement/#2-rvalues-et-rvalue-references-1

            Je vais jeter un œil a tes liens, merci !

            • Partager sur Facebook
            • Partager sur Twitter
              5 juin 2020 à 21:58:04

              C'est bien montré dans la doc que je t'ai fourni, std::move() attend une r-value reference... Et la collision de référence fait qu'une l-value reference "convertie" en r-value reference donne une l-value reference. D'ou le principe de perfect forwarding.

              Oh mais c'est la suite du cours !! Je vais bouffer du ZDS moi ce soir ! Ca fait longtemps que j'attends ça.

              -
              Edité par Daimyo_ 5 juin 2020 à 22:02:03

              • Partager sur Facebook
              • Partager sur Twitter
                5 juin 2020 à 22:15:12

                Daimyo_ a écrit:

                C'est bien montré dans la doc que je t'ai fourni, std::move() attend une r-value reference... Et la collision de référence fait qu'une l-value reference "convertie" en r-value reference donne une l-value reference. D'ou le principe de perfect forwarding.

                Oh mais c'est la suite du cours !! Je vais bouffer du ZDS moi ce soir ! Ca fait longtemps que j'attends ça.

                -
                Edité par Daimyo_ il y a 2 minutes

                Ca ne semble pas provenir du std::move j'ai l'erreur meme sans et pis si ca venait de ca l'erreur ressemblerais probablement a "Impossible de convertir l'argument"

                De plus je ne vois pas vraiment ou c'est marqué qu'elle attend un r-value vu que c'est marqué que justement c'est un équivalent a static_cast vers une r-value
                "In particular, std::move produces an xvalue expression that identifies its argument t. It is exactly equivalent to a static_cast to an rvalue reference type."
                et meme dans l'exemple c'est une l-value qui est utilisé:

                 std::string str = "Hello"; //ici
                    std::vector<std::string> v;
                 
                    // uses the push_back(const T&) overload, which means 
                    // we'll incur the cost of copying str
                    v.push_back(str);
                    std::cout << "After copy, str is \"" << str << "\"\n";
                 
                    // uses the rvalue reference push_back(T&&) overload, 
                    // which means no strings will be copied; instead, the contents
                    // of str will be moved into the vector.  This is less
                    // expensive, but also means str might now be empty.
                    v.push_back(std::move(str));//et ici
                    std::cout << "After move, str is \"" << str << "\"\n";
                 
                    std::cout << "The contents of the vector are \"" << v[0]
                                                         << "\", \"" << v[1] << "\"\n";
                et sinon oui c'est la suite du cours mais elle est en beta donc il peut y avoir des modifications(d'ailleurs la partie sur la poo n'est pas terminé)

                -
                Edité par Kiwi_Dch 5 juin 2020 à 22:18:37

                • Partager sur Facebook
                • Partager sur Twitter
                  5 juin 2020 à 22:21:28

                  std::move est un cast en une rvalue et std::forward n'est utile qu'avec des templates. La notation T&& de la doc de std::move ne fait pas référence à une rvalue, mais à une référence universelle: soit une rvalue, soit une lvalue. Cela n'est valide qu'à la condition que T soit un type template pleinement déduit. Il y a un cours sur le sujet sur zds.

                  Pour l'erreur, elle vient de l’initialisation du vecteur. La construction avec {make_unique...} passe par le constructeur qui prend un std::initializer_list qui référence des valeurs constantes. Il est donc impossible de construire un vecteur ainsi puisque les valeurs ne pourront pas être déplacées.

                  (std::initializer_list est très mal fichu)

                  Donc, soit on enchaîne les push_back/emplace_back, soit on utilise un intermédiaire pour tout construire en 1 ligne:

                  #include <algorithm>
                  #include <memory>
                  #include <vector>
                  
                  struct Poisson {};
                  
                  template<class T, std::size_t N>
                  std::vector<T> to_vector(T(&&a)[N])
                  {
                    return std::vector(std::make_move_iterator(a), std::make_move_iterator(a+N));
                  }
                  
                  int main()
                  {
                    auto vec = to_vector({std::make_unique<Poisson>(), std::make_unique<Poisson>(), /*...*/});
                  }

                  Attention aux avertissements:

                  test.cpp:34:55: warning: suggest parentheses around ‘&&’ within ‘||’ [-Wparentheses]
                     34 |  assert(sexe == Sexe::Femelle || m_sexe == Sexe::Male && "Le sexe doit etre valide");
                        |                                  ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                  

                  -
                  Edité par jo_link_noir 5 juin 2020 à 22:25:08

                  • Partager sur Facebook
                  • Partager sur Twitter
                    5 juin 2020 à 22:23:47

                    T'as pas lu les liens que je t'ai donné ! En tous cas j'ai simulé la situation dans laquelle tu étais, j'ai obtenu le même problème: c'est à dire le compilo me disait bien que le constructeur de copie de std::unique_ptr avait été supprimé et que j'essayais de l'appeler. J'ai appliqué le perfect forwarding sur ma l-value reference et ça a fonctionné. Libre à toi de ne pas le faire mais voilà... (après edit: bah du coup c'est pas une solution... mais comment ça se fait que je n'ai plus d'erreur de compilation ??)

                    Sinon tu aurais du essayer la technique avec les pointeurs partagés car ça fonctionne, un pointeur partagé permet la copie, pas les pointeurs uniques.

                    Dans ce cas ci je pense que l'objet std::unique_ptr est copié et non déplacé comme tu le veux.

                    =====

                    @jo_link_noir je viens de lire ton message. D'accord je n'avais pas compris ça. Merci, du coup je formate mon avis là dessus.

                    -
                    Edité par Daimyo_ 5 juin 2020 à 22:30:11

                    • Partager sur Facebook
                    • Partager sur Twitter
                      5 juin 2020 à 22:29:10

                      (Lire mon message précédent, mais)

                      > J'ai appliqué le perfect forwarding sur ma l-value reference et ça a fonctionné.

                      Sans template on ne peut pas parler de perfect forwarding

                      > Comme dit dans le cours de ZDS, std::move déplace une donnée dans le tas et COPIE une donnée dans la pile

                      Ce n'est pas ce que fait std::move, et de mémoire, ce n'est pas ce que dit le cours non plus.

                      • Partager sur Facebook
                      • Partager sur Twitter
                        5 juin 2020 à 22:30:55

                        Le parametre de std::move n'est pas une r-value reference mais une universal reference. cf ici

                        Sinon le problème vient de la ligne 6 de ton main. Je n'ai pas trouvé de moyen de le faire en une ligne, mais en plusieurs lignes ça donne ça:

                        std::vector<std::unique_ptr<Poisson>> poissons;
                        poissons.push_back(std::make_unique<Poisson>("Gerard", Sexe::Male));

                        Sinon je n'ai pas lu la repose de koala01 mais en général ses réponses sont au top du top.

                        Edit: trop tard....

                        jo_link_noir a écrit:

                        Pour l'erreur, elle vient de l’initialisation du vecteur. La construction avec {make_unique...} passe par le constructeur qui prend un std::initializer_list qui référence des valeurs constantes. Il est donc impossible de construire un vecteur ainsi puisque les valeurs ne pourront pas être déplacées.

                        J'étais en train de bugger la dessus. Pourquoi les valeurs sont constantes? C'est précisé nulle part AFAIK.

                        -
                        Edité par eugchriss 5 juin 2020 à 22:32:47

                        • Partager sur Facebook
                        • Partager sur Twitter

                        Eug

                          5 juin 2020 à 22:46:54

                          > J'étais en train de bugger la dessus. Pourquoi les valeurs sont constantes? C'est précisé nulle part AFAIK.

                          https://en.cppreference.com/w/cpp/utility/initializer_list

                          An object [...] that provides access to an array of objects of type const T.

                          • Partager sur Facebook
                          • Partager sur Twitter
                            5 juin 2020 à 22:48:48

                            jo_link_noir a écrit:

                            > J'étais en train de bugger la dessus. Pourquoi les valeurs sont constantes? C'est précisé nulle part AFAIK.

                            https://en.cppreference.com/w/cpp/utility/initializer_list

                            An object [...] that provides access to an array of objects of type const T.

                            Ahah! La premiere ligne en plus.

                            • Partager sur Facebook
                            • Partager sur Twitter

                            Eug

                              5 juin 2020 à 23:23:41

                              jo_link_noir a écrit:

                              std::move est un cast en une rvalue et std::forward n'est utile qu'avec des templates. La notation T&& de la doc de std::move ne fait pas référence à une rvalue, mais à une référence universelle: soit une rvalue, soit une lvalue. Cela n'est valide qu'à la condition que T soit un type template pleinement déduit. Il y a un cours sur le sujet sur zds.

                              Pour l'erreur, elle vient de l’initialisation du vecteur. La construction avec {make_unique...} passe par le constructeur qui prend un std::initializer_list qui référence des valeurs constantes. Il est donc impossible de construire un vecteur ainsi puisque les valeurs ne pourront pas être déplacées.

                              (std::initializer_list est très mal fichu)

                              Donc, soit on enchaîne les push_back/emplace_back, soit on utilise un intermédiaire pour tout construire en 1 ligne:

                              #include <algorithm>
                              #include <memory>
                              #include <vector>
                              
                              struct Poisson {};
                              
                              template<class T, std::size_t N>
                              std::vector<T> to_vector(T(&&a)[N])
                              {
                                return std::vector(std::make_move_iterator(a), std::make_move_iterator(a+N));
                              }
                              
                              int main()
                              {
                                auto vec = to_vector({std::make_unique<Poisson>(), std::make_unique<Poisson>(), /*...*/});
                              }

                              Attention aux avertissements:

                              test.cpp:34:55: warning: suggest parentheses around ‘&&’ within ‘||’ [-Wparentheses]
                                 34 |  assert(sexe == Sexe::Femelle || m_sexe == Sexe::Male && "Le sexe doit etre valide");
                                    |                                  ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                              

                              -
                              Edité par jo_link_noir il y a environ 1 heure

                              Merci, j'y vois un peu plus clair et je ne pensais pas du tout que l'erreur viendrait de la c'est vrai que ça n'a pas l'air d’être très bien fichu c'est bon a savoir, je n'avais pas de warn(j'ai mis lv4) mais j'ai rajouter des () donc ça devrait être bon, mais je vais tout de même faire une fonction ajouter comme koala1 a montré

                              • Partager sur Facebook
                              • Partager sur Twitter
                                6 juin 2020 à 1:31:20

                                Kiwi_Dch a écrit:

                                Pour la responsabilité je n'ai pas bien compris ce que l'utilisateur peut bien faire comme connerie parce que dans le pire des cas le code ne se compile pas(je pense)

                                Heuu... voyons un peu...

                                Que penses tu d'un essai du genre de

                                Type foo(Acuarium & a){
                                    Poisson * p = new Poisson(/ ... */);
                                    /* du code qui pourrait lancer exception ici */
                                    a.ajouterPoisson(p);
                                    /*...*/
                                }

                                qui ne compilera effectivement pas dans, du fait du passage par référence, mais qui compilerait sans problème si ta fonction prenait son paramètre sous la forme de std::unique_ptr &&, qui n'empêcherait pas les fuites mémoires :'(.

                                Tout cela à cause de la deuxième esperluette... Voilà qui fait cher au caractère de code, tu ne trouves pas?

                                Et puis, de manière générale, ce n'est pas parce que "je ne vois pas quel problème pourrait survenir" que cela signifie forcément qu'il n'y aura jamais aucun problème.

                                Cela veut juste dire que les problèmes qui risquent d'apparaitre n'ont pas encore été identifiés ;)

                                • Partager sur Facebook
                                • Partager sur Twitter
                                Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait

                                Tentative de référencement d'une fonction supprimé

                                × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                • Editeur
                                • Markdown