0

I made a post that will be an extention to this here. I know have a bit better of an understanding when to use unique_ptr and when not to. Although, stressing the bit there I am still getting some errors most likely associated to not understanding unique_ptr well enough.

Here is the errors I am getting:

1>------ Build started: Project: LinkedList, Configuration: Debug Win32 ------
1>main.cpp
1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(166): error C2679: binary '=': no operator found which takes a right-hand operand of type 'SingleLinkedList<int>::Node *' (or there is no acceptable conversion)
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.14.26428\include\memory(2309): note: could be 'std::unique_ptr<SingleLinkedList<int>::Node,std::default_delete<_Ty>> &std::unique_ptr<_Ty,std::default_delete<_Ty>>::operator =(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)'
1>        with
1>        [
1>            _Ty=SingleLinkedList<int>::Node
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.14.26428\include\memory(2247): note: or       'std::unique_ptr<SingleLinkedList<int>::Node,std::default_delete<_Ty>> &std::unique_ptr<_Ty,std::default_delete<_Ty>>::operator =(std::unique_ptr<_Ty,std::default_delete<_Ty>> &&) noexcept'
1>        with
1>        [
1>            _Ty=SingleLinkedList<int>::Node
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.14.26428\include\memory(2173): note: or       'std::unique_ptr<SingleLinkedList<int>::Node,std::default_delete<_Ty>> &std::unique_ptr<_Ty,std::default_delete<_Ty>>::operator =(std::nullptr_t) noexcept'
1>        with
1>        [
1>            _Ty=SingleLinkedList<int>::Node
1>        ]
1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(166): note: while trying to match the argument list '(std::unique_ptr<SingleLinkedList<int>::Node,std::default_delete<_Ty>>, SingleLinkedList<int>::Node *)'
1>        with
1>        [
1>            _Ty=SingleLinkedList<int>::Node
1>        ]
1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(163): note: while compiling class template member function 'void SingleLinkedList<int>::deleteHead(void)'
1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(85): note: see reference to function template instantiation 'void SingleLinkedList<int>::deleteHead(void)' being compiled
1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(83): note: while compiling class template member function 'SingleLinkedList<int>::~SingleLinkedList(void)'
1>cI made a post that will be an extention to this [enter link description here][1]:\dev\linkedlist\linkedlist\main.cpp(23): note: see reference to function template instantiation 'SingleLinkedList<int>::~SingleLinkedList(void)' being compiled
1>c:\dev\linkedlist\linkedlist\main.cpp(23): note: see reference to class template instantiation 'SingleLinkedList<int>' being compiled
1>Done building project "LinkedList.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

I should mention again I am new to MS visual studio C++ and unique_ptr as well. I originally wrote this implementation using just new pointers but I was suggested to rewrite it using unique_ptr.

Here is my header file:

#ifndef SingleLinkedList_h
#define SingleLinkedList_h

#include <iostream>

template <class T>
class SingleLinkedList {
private:

    struct Node {
        T data;
        std::unique_ptr<Node> next = nullptr;
        Node(T x) : data(x), next(nullptr) {}
    };
    std::unique_ptr<Node> head = nullptr;
    std::unique_ptr<Node> tail = nullptr;

    // This function is for the overloaded operator << 
    void display(std::ostream &str) const {
        for (Node* loop = head.get(); loop != nullptr; loop = loop->next.get()) {
            str << loop->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;
    bool empty() const { return head.get() == nullptr; }
    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 <class T>
SingleLinkedList<T>::SingleLinkedList(SingleLinkedList<T> const &source) {
    for(Node* loop = source->head.get(); loop != nullptr; loop = loop->next.get()) {
        push(loop->data);
    }
}

template <class T>
SingleLinkedList<T>::SingleLinkedList(SingleLinkedList<T>&& move) noexcept {
    move.swap(*this);
}

template <class T>
SingleLinkedList<T>& SingleLinkedList<T>::operator=(SingleLinkedList<T> &&move) noexcept {
    move.swap(*this);
    return *this;
}

template <class T>
SingleLinkedList<T>::~SingleLinkedList() {
    while (head != nullptr) {
        deleteHead();
    }
}

template <class T>
SingleLinkedList<T>& SingleLinkedList<T>::operator=(SingleLinkedList const &rhs) {
    SingleLinkedList copy{ rhs };
    swap(copy);
    return *this;
}

template <class T>
void SingleLinkedList<T>::swap(SingleLinkedList &other) noexcept {
    using std::swap;
    swap(head, other.head);
    swap(tail, other.tail);
}

template <class T>
void SingleLinkedList<T>::push(const T &theData) {
    std::unique_ptr<Node> newNode = std::make_unique<Node>(theData);

    if (head == nullptr) {
        head = std::move(newNode);
        tail = head.get();
    }

    else {
        tail->next = std::move(newNode);
        tail = tail->next.get();
    }
}

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


template <class T>
void SingleLinkedList<T>::display() const {
    Node* newNode = head.get();
    while (newNode != nullptr) {
        std::cout << newNode->data << "\t";
        newNode = newNode->next;
    }
}

template <class T>
void SingleLinkedList<T>::insertHead(const T &theData) {
    std::unique_ptr<Node> newNode = std::make_unique<Node>(theData);
    newNode->next = head.get();
    head = newNode;
}

template <class T>
void SingleLinkedList<T>::insertTail(const T &theData) {
    std::unique_ptr<Node> newNode = std::make_unique<Node>(theData);
    tail->next = newNode;
    tail = newNode;
}

template <class T>
void SingleLinkedList<T>::insertPosition(int pos, const T &theData) {

}

template <class T>
void SingleLinkedList<T>::deleteHead() {
    Node* old = head.get();
    delete old;
    head = head->next.get();
}

template <class T>
void SingleLinkedList<T>::deleteTail() {

}

template <class T>
void SingleLinkedList<T>::deletePosition(int pos) {

}

template <class T>
bool SingleLinkedList<T>::search(const T &x) {

}




#endif /* SingleLinkedList_h*/

Here is the main.cpp file:

#include <algorithm>
#include <cassert>
#include <iostream>
#include <ostream>
#include <iosfwd>
#include "SingleLinkedList.h"


int main(int argc, const char * argv[]) {


    ///////////////////////////////////////////////////////////////////////
    ///////////////////////////// Single Linked List //////////////////////
    ///////////////////////////////////////////////////////////////////////
    SingleLinkedList<int> 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();
}

1 Answers1

1

It doesn't make sense to use unique pointers for Linked List. For exercise purpose, you can use raw pointers. For practical purpose, use std::list or other containers.

The reason it doesn't make sense is that your tail could point to same Node withe another Node's next. Then it is not unique.

Hai Bi
  • 1,173
  • 1
  • 11
  • 21
  • Okay, thank you. Just for reference what data structures should I use unique pointers for if I was going to rewrite them from scratch? –  Jul 26 '18 at 02:19
  • First, if you make tail as a raw pointer, you still could achieve the goal by make minor fixes. – Hai Bi Jul 26 '18 at 02:22
  • Is it necessary though, I have written a class like this using just raw pointers that worked well for me. I was just recommended to use std::unique_ptr. Is there certain data structures where I should use unique pointers? Such as a Stack, Queue, etc... –  Jul 26 '18 at 02:24
  • second, unique pointer can be used as a class member to store data for any of your own class (other class), if you don't want to worry about when to release the memory. But you need to handle how this data is copied since unique_ptr can't be copied. – Hai Bi Jul 26 '18 at 02:24
  • Thank you for your comments but I think you are missing the point to my question. –  Jul 26 '18 at 02:25
  • If you are recommended by teacher to use unique_ptr, then change tail to raw pointer. There are some minor fixes such as to use std::move, and remove delete. One example is to fix deleteHead to this: Node* old = head.get(); auto next = std::move(old->next); head = std::move(next); – Hai Bi Jul 26 '18 at 02:28
  • I was recommended by other people on Code Review SE. But thank you. –  Jul 26 '18 at 02:29
  • @Snorrlaxxx So maybe the correct course of action is to understand the suggestion before blindly trying to implement it? You've missed the point of `unique_ptr`; instead of trying to find things you can use it for, focus on the best solution for the actual problems you're having. – Bartek Banachewicz Jul 26 '18 at 06:41
  • @Snorrlaxxx My apologies for not being clear enough in the answer linked in your question that `tail` needed to be a plain old raw pointer. [Herb Sutter's Leak Free By Design presentation.](https://www.youtube.com/watch?v=JfmTagWcqoE) Lays out a compelling case for using smart pointers, when to use them, and how to use them. Probably not the most fun hour and forty minutes in your life, but has the potential to save you far more than an hour and forty minutes over the course of a programming career. Time you can spend having fun. – user4581301 Jul 26 '18 at 23:01
  • @user4581301 Thank you I will give it a read now, so shouldn't use a raw pointer for the tail in the linked post? –  Jul 26 '18 at 23:05
  • @Snorrlaxxx The last item in the list is doomed to be pointed at twice--once by the second last item in the list's `next` and one by `tail`--they can't both be `unique_ptr`. `next` has to be a `unique_ptr`, so that leaves `tail` to be the raw pointer. – user4581301 Jul 26 '18 at 23:44