Liste simple liée générique utilisant std :: unique_ptr, erreurs de décompilation inconnues dans Microsoft Visual Studio C ++

Je suis très nouveau dans Microsoft Visual Studio C ++ ainsi que dans std :: unique_ptr. Sur CodeReview, il m’a été recommandé de réécrire à l’aide de std :: unique_ptr. Vous pouvez trouver la question à laquelle je fais référence ici .

Voici les erreurs suivantes que je reçois:

1>main.cpp 1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(26): error C2760: syntax error: unexpected token 'identifier', expected ';' 1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(61): note: see reference to class template instantiation 'SingleLinkedList' being comstackd 1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(65): error C2760: syntax error: unexpected token 'identifier', expected ';' 1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(104): error C2760: syntax error: unexpected token 'identifier', expected ';' 1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(104): error C7510: 'make_unique': use of dependent type name must be prefixed with 'typename' 1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(120): error C2760: syntax error: unexpected token 'identifier', expected ';' 1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(120): error C7510: 'make_unique': use of dependent type name must be prefixed with 'typename' 1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(136): error C2760: syntax error: unexpected token 'identifier', expected ';' 1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(136): error C7510: 'make_unique': use of dependent type name must be prefixed with 'typename' 1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(145): error C2760: syntax error: unexpected token 'identifier', expected ';' 1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(145): error C7510: 'make_unique': use of dependent type name must be prefixed with 'typename' 1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(152): error C2760: syntax error: unexpected token 'identifier', expected ';' 1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(152): error C7510: 'make_unique': use of dependent type name must be prefixed with 'typename' 1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(164): error C2760: syntax error: unexpected token 'identifier', expected ';' 1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(164): error C7510: 'make_unique': use of dependent type name must be prefixed with 'typename' 1>Done building project "LinkedList.vcxproj" -- FAILED. ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ========== 

Voici le fichier d’en-tête:

 #ifndef SingleLinkedList_h #define SingleLinkedList_h #include  template  class SingleLinkedList { private: struct Node { T data; std::unique_ptr next = nullptr; Node(T x) : data(x), next(nullptr) {} }; std::unique_ptr head = nullptr; std::unique_ptr tail = nullptr; // This function is for the overloaded operator << void display(std::ostream &str) const { for (std::make_unique loop = head; loop != nullptr; loop = loop->next) { str <data << "\t"; } str << "\n"; } public: // Constructors SingleLinkedList() = default; // empty constructor SingleLinkedList(SingleLinkedList const &source); // copy constructor // Rule of 5 SingleLinkedList(SingleLinkedList &&move) noexcept; // move constructor SingleLinkedList& operator=(SingleLinkedList &&move) noexcept; // move assignment operator ~SingleLinkedList(); // Overload operators SingleLinkedList& operator=(SingleLinkedList const &rhs); friend std::ostream& operator<<(std::ostream &str, SingleLinkedList &data) { data.display(str); return str; } // Memeber functions void swap(SingleLinkedList &other) noexcept; void push(const T &theData); void push(T &&theData); void display() const; void insertHead(const T &theData); void insertTail(const T &theData); void insertPosition(int pos, const T &theData); void deleteHead(); void deleteTail(); void deletePosition(int pos); bool search(const T &x); }; template  SingleLinkedList::SingleLinkedList(SingleLinkedList const &source) { for(std::make_unique loop = source->head; loop != nullptr; loop = loop->next) { push(loop->data); } } template  SingleLinkedList::SingleLinkedList(SingleLinkedList&& move) noexcept { move.swap(*this); } template  SingleLinkedList& SingleLinkedList::operator=(SingleLinkedList &&move) noexcept { move.swap(*this); return *this; } template  SingleLinkedList::~SingleLinkedList() { while (head != nullptr) { deleteHead(); } } template  SingleLinkedList& SingleLinkedList::operator=(SingleLinkedList const &rhs) { SingleLinkedList copy{ rhs }; swap(copy); return *this; } template  void SingleLinkedList::swap(SingleLinkedList &other) noexcept { using std::swap; swap(head, other.head); swap(tail, other.tail); } template  void SingleLinkedList::push(const T &theData) { std::make_unique newNode = Node(theData); if (head == nullptr) { head = newNode; tail = newNode; newNode = nullptr; } else { tail->next = newNode; tail = newNode; } } template  void SingleLinkedList::push(T &&theData) { std::make_unique newNode = Node(std::move(theData)); if (head == nullptr) { head = newNode; tail = newNode; newNode = nullptr; } else { tail->next = newNode; tail = newNode; } } template  void SingleLinkedList::display() const { std::make_unique newNode = head; while (newNode != nullptr) { std::cout <data <next; } } template  void SingleLinkedList::insertHead(const T &theData) { std::make_unique newNode = Node(theData); newNode->next = head; head = newNode; } template  void SingleLinkedList::insertTail(const T &theData) { std::make_unique newNode = Node(theData); tail->next = newNode; tail = newNode; } template  void SingleLinkedList::insertPosition(int pos, const T &theData) { } template  void SingleLinkedList::deleteHead() { std::make_unique old = head; head = head->next; delete old; } template  void SingleLinkedList::deleteTail() { } template  void SingleLinkedList::deletePosition(int pos) { } template  bool SingleLinkedList::search(const T &x) { } #endif /* SingleLinkedList_h*/ 

Voici le fichier main.cpp:

 #include  #include  #include  #include  #include  #include "SingleLinkedList.h" int main(int argc, const char * argv[]) { /////////////////////////////////////////////////////////////////////// ///////////////////////////// Single Linked List ////////////////////// /////////////////////////////////////////////////////////////////////// SingleLinkedList obj; obj.push(2); obj.push(4); obj.push(6); obj.push(8); obj.push(10); std::cout<<"\n--------------------------------------------------\n"; std::cout<<"---------------displaying all nodes---------------"; std::cout<<"\n--------------------------------------------------\n"; std::cout << obj << std::endl; // // std::cout<<"\n--------------------------------------------------\n"; // std::cout<<"-----------------Inserting At End-----------------"; // std::cout<<"\n--------------------------------------------------\n"; // obj.insertTail(20); // std::cout << obj << std::endl; // // std::cout<<"\n--------------------------------------------------\n"; // std::cout<<"----------------Inserting At Start----------------"; // std::cout<<"\n--------------------------------------------------\n"; // obj.insertHead(50); // std::cout << obj << std::endl; // // std::cout<<"\n--------------------------------------------------\n"; // std::cout<<"-------------Inserting At Particular--------------"; // std::cout<<"\n--------------------------------------------------\n"; // obj.insertPosition(5,60); // std::cout << obj << std::endl; // // std::cout<<"\n--------------------------------------------------\n"; // std::cout<<"----------------Deleting At Start-----------------"; // std::cout<<"\n--------------------------------------------------\n"; // obj.deleteHead(); // std::cout << obj << std::endl; // // std::cout<<"\n--------------------------------------------------\n"; // std::cout<<"----------------Deleting At End-----------------"; // std::cout<<"\n--------------------------------------------------\n"; // obj.deleteTail(); // std::cout << obj << std::endl; // // // std::cout<<"\n--------------------------------------------------\n"; // std::cout<<"--------------Deleting At Particular--------------"; // std::cout<<"\n--------------------------------------------------\n"; // obj.deletePosition(4); // std::cout << obj << std::endl; // std::cout << std::endl; // // obj.search(8) ? printf("Yes"):printf("No"); std::cin.get(); } 

Je suppose que la plupart des erreurs sont des erreurs de syntaxe ou que je viens de commettre des erreurs négligentes. Merci.

La majeure partie de vos erreurs de syntaxe sont des dérivés de la même erreur, regardons donc la première. C’est très instructif, car il signale DEUX erreurs. Chaque fois que vous pouvez tuer deux cailloux avec un seul oiseau, je vous invite à le faire C’est sacrément difficile de tuer une pierre dans le meilleur des cas.

 void display(std::ostream &str) const { for (std::make_unique loop = head; loop != nullptr; loop = loop->next) { str << loop->data << "\t"; } str << "\n"; } 

Dans std::make_unique loop = head , std::make_unique est une fonction qui vous donne un std::unique_ptr . Ce n'est pas un type que vous pouvez utiliser pour déclarer une variable. Cette erreur est répétée plusieurs fois dans le code et le nettoyage de chacune d'elles révélera un tas de nouvelles erreurs. Yay amusant.

Première étape, remplaçons la fonction par le type correct.

 void display(std::ostream &str) const { for (std::unique_ptr loop = head; loop != nullptr; loop = loop->next) { str << loop->data << "\t"; } str << "\n"; } 

Sensationnel. Simple. Malheureusement ça ne marche pas. std::unique_ptr loop = head signifie que vous avez maintenant deux unique_ptr sur le même object. Cela ne semble pas particulièrement unique et le compilateur ne le permettra pas. Vous obtiendrez probablement un message d'erreur obscur concernant une fonction supprimée. En effet, les constructeurs de copie et opérateur = unique_ptr de unique_ptr ont été bannis de la dimension sombre pour rendre plus difficile la liquidation accidentelle de plusieurs unique_ptr .

Un petit mot sur l’importance de tout cela: L’appropriation L'un des plus gros problèmes avec les pointeurs est de décider qui delete quoi et quand. Pour résoudre ce problème, vous établissez la propriété d'un pointeur. Peut-être que le pointeur est sur une variable automatique et que la stack ou tout ce qui est utilisé pour gérer les données automatiques s'en chargera. Vous delete RIEN! Muhuhahahaha! Peut-être quelqu'un de new ed la variable. Quelqu'un doit le delete . Ce quelqu'un est le propriétaire. Certains imbéciles peuvent même avoir malloc ed l'object. Quelqu'un doit le free au lieu de le delete . Encore une fois, c'est le propriétaire.

Il n'y a aucun moyen pratique de déterminer comment l'object a été alloué et comment il doit être supprimé à partir d'un pointeur. Tout ce qu'un pointeur fait, c'est un point. Le programmeur doit établir un contrat indiquant qui, le cas échéant, s’occupe de lui et de quelle manière. Dans les temps anciens, cela pouvait être un processus laborieux.

L'histoire a montré qu'il est difficile de gérer correctement un pointeur basé sur un contrat. Et si vous le faites bien, le prochain programmeur à venir peut complètement le faire. La gestion des pointeurs fonctionne beaucoup mieux lorsque le contrat prévoit une application automatisée.

Aujourd'hui, nous utilisons un pointeur intelligent. Il y a un tas de pointeurs intelligents. Nous nous en tenons à unique_ptr cette fois. Si vous voulez en savoir plus, lisez Qu'est-ce qu'un pointeur intelligent et quand dois-je en utiliser un?

unique_ptr est le propriétaire. Il s’agit d’une ancienne et simple variable automatique qui contient un pointeur qui sera publié dès que unique_ptr hors de scope. Pas plus de soucis de propriété. Le propriétaire est explicite. Et comme le Highlander, il ne peut y en avoir qu'un. . Si vous avez deux unique_ptr sur le même object, ce n'est pas si unique, n'est-ce pas? Avec deux propriétaires, l'un irait d'abord hors de scope et détruirait l'object, laissant à l'autre propriétaire une bombe à retardement.

Ne pas new un unique_ptr . Cela défait complètement le point.

Vous ne pouvez pas copier un unique_ptr , mais vous pouvez transférer la propriété avec std::move . Notez que l’object, le cas échéant, appartenant actuellement à la destination unique_ptr sera détruit.

Si vous appelez une fonction qui reçoit un unique_ptr , vous devrez transférer la propriété au paramètre de la fonction de réception. Le pointeur va maintenant être détruit la fonction retourne, en supposant qu'elle ne transfère pas la propriété du pointeur ailleurs Comme vous ne voulez souvent pas que cela se produise, mais que vous souhaitiez tout de même que la propriété du pointeur rest vide, transmettez unique_ptr par référence.

Vous pouvez également utiliser la méthode unique_ptr::get pour obtenir un pointeur brut non utilisé, mais quiconque vous le donnez doit savoir qu'il doit laisser le pointeur seul, ce qui nous ramène à la gestion de pointeur basée sur un contrat.

Huh. Ce n'était pas tout ce que rapide, était-ce? Désolé pour ça.

Pour revenir sur le sujet, votre pointeur appartient à un unique_ptr . Vous ne pouvez pas simplement faire une nouvelle copie avec std::unique_ptr loop = head; , Loi des Highlanders, ci-dessus. Transfert de propriété vers une variable automatique étroitement définie qui mourra et détruira le pointeur à la fin de la boucle avec std::unique_ptr loop = std::move(head); laisserait le pointeur principal pointant vers rien. Pas utile. La liste chaînée est ruinée, mais au moins tout ce qu’elle a été détruit "correctement".

Comme discuté ci-dessus, vous pouvez utiliser une référence ou get . Vous ne pouvez pas redéfinir la référence avec loop = loop->next . La référence ne peut donc pas fonctionner. Cela laisse get

 void display(std::ostream &str) const { for (Node* loop = head.get(); loop != nullptr; loop = loop->next.get()) { str << loop->data << "\t"; } str << "\n"; } 

Il y a très peu de place dans laquelle le programmeur peut être dérouté par le pointeur brut ici et la propriété est toujours garantie par unique_ptr , donc tout devrait bien se passer.

Ce problème est répété dans

 template  SingleLinkedList::SingleLinkedList(SingleLinkedList const &source) { for(std::make_unique loop = source->head; loop != nullptr; loop = loop->next) { push(loop->data); } } 

Même solution.

Il existe une variante dans les deux méthodes push

 template  void SingleLinkedList::push(const T &theData) { std::make_unique newNode = Node(theData); if (head == nullptr) { head = newNode; tail = newNode; newNode = nullptr; } else { tail->next = newNode; tail = newNode; } } 

Solution (en quelque sorte):

 template  void SingleLinkedList::push(const T &theData) { std::unique_ptr newNode = std::make_unique(theData); if (head == nullptr) { head = newNode; tail = newNode; newNode = nullptr; } else { tail->next = newNode; tail = newNode; } } 

Mais notez les affectations à la head et à la tail . Cela viole Highlander et doit être corrigé. Vous pouvez transférer la propriété de newNode dans head , mais il ne newNode alors plus rien à donner. Et pourquoi tail devrait-il devenir propriétaire de quelque chose? Quels que soient les points de la tail doivent appartenir à la head ou au next Node . Sa propriété est garantie. Comme il est confiné dans SingleLinkedList il conclut un contrat avec lui-même et peut s'en tirer en étant simplement un ancien pointeur.

Cela signifie

 Node* tail = nullptr; 

et

 template  void SingleLinkedList::push(const T &theData) { std::unique_ptr newNode = std::make_unique(theData); if (head == nullptr) { head = std::move(newNode); tail = head.get(); } else { tail->next = std::move(newNode); tail = tail->next.get(); } } 

Je n'ai plus de temps, mais

 void SingleLinkedList::insertHead(const T &theData) 

et

 void SingleLinkedList::insertTail(const T &theData) { 

doivent être mis à jour dans le nouvel ordre mondial et prendre en compte "Et si la liste est vide?"