1

This is my code :

#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include "dummy.h"
using namespace std;

#ifndef SORT_H
#define SORT_H

template <class T>
class LinkedList {
    struct Node {
        T data;
        Node * next;
    };

    Node * head;

public:
    LinkedList() {
        head = NULL;
    }
    LinkedList(T value) {
        head -> data = value;
        head -> next = NULL;
    }

    ~LinkedList() {
        while(head != NULL) {
            Node * n = head->next;
            delete head;
            head = n;
        }
    }

    void add(T value) {
        Node * n = new Node;  // the error starts here probably
        n->data = value;
        n->next = head;
        head = n;
    }

    void print() {
        Node *curr = head;
        while (curr) {
            cout << curr->data << endl;
            curr = curr->next;
        }
    }
};

#endif

and when I try to compile it I get the error: use of deleted function 'LinkedList::Node::Node()'

I understand that it is probably because I can't know before-hand if I will get any arguments while creating the sorted list or not, how can I do that? To make it compile and run?

The Dummy class is like that:

#include <iostream>
#include <cstring>
#include <string>
#include <cmath>

using namespace std;

#ifndef DUMB_H
#define DUMB_H

class Dummy {
    int num_of_teeth;
public:
    Dummy(int num) {
        num_of_teeth = num;
    }
    ~Dummy() {};
    void add(int num) {
        num_of_teeth += num;
    }
    void remove() {
        num_of_teeth --;
    }
    void print() {
        int num = num_of_teeth;
        while (num > 0) {
            cout << "D";
            if ((num-1) == (num_of_teeth/2)) {
                cout << "\n";
            }
            num --;
            if (num == 0) {
                cout << "\n";
            }
        }
    }
    friend ostream& operator << (ostream& output, Dummy& dumb)
    {
        output << dumb.num_of_teeth;
        return output;
    }
};

#endif

My main is:

#include <iostream>
#include "sortedList.h"
#include "dummy.h"

int main() {
    std::cout << "Hello, World!" << std::endl;

    Dummy teeth(24);
    teeth.add(7);
    Dummy slime(11);
    slime.add(1);
    Dummy josh(32);
    LinkedList<Dummy> teeth_list;
    teeth_list.add(teeth);  // The first time I try to put teeth into the list
    teeth_list.add(slime);
    teeth_list.add(josh);
    teeth_list.print();

    LinkedList <string> myList;
    myList.add("yossi");
    myList.add("Rikki");
    myList.add("Pavel <3");
    myList.print();

    return 0;
}

The build log:

====================[ Build | exe_name | Debug ]================================
"C:\Program Files\JetBrains\CLion 2021.1.1\bin\cmake\win\bin\cmake.exe" --build C:\Users\User\CLionProjects\ex2.2\cmake-build-debug --target exe_name -- -j 3
Scanning dependencies of target exe_name
[ 33%] Building CXX object CMakeFiles/exe_name.dir/main.cpp.obj
[ 66%] Building CXX object CMakeFiles/exe_name.dir/sortedList.cpp.obj
In file included from C:\Users\User\CLionProjects\ex2.2\main.cpp:2:
C:\Users\User\CLionProjects\ex2.2\sortedList.h: In instantiation of 'void LinkedList<T>::add(T) [with T = Dummy]':
C:\Users\User\CLionProjects\ex2.2\main.cpp:14:25:   required from here
C:\Users\User\CLionProjects\ex2.2\sortedList.h:38:20: error: use of deleted function 'LinkedList<Dummy>::Node::Node()'
         Node * n = new Node;
                    ^~~~~~~~
C:\Users\User\CLionProjects\ex2.2\sortedList.h:13:12: note: 'LinkedList<Dummy>::Node::Node()' is implicitly deleted because the default definition would be ill-formed:
     struct Node {
            ^~~~
C:\Users\User\CLionProjects\ex2.2\sortedList.h:13:12: error: no matching function for call to 'Dummy::Dummy()'
In file included from C:\Users\User\CLionProjects\ex2.2\sortedList.h:5,
                 from C:\Users\User\CLionProjects\ex2.2\main.cpp:2:
C:\Users\User\CLionProjects\ex2.2\dummy.h:14:5: note: candidate: 'Dummy::Dummy(int)'
     Dummy(int num) {
     ^~~~~
C:\Users\User\CLionProjects\ex2.2\dummy.h:14:5: note:   candidate expects 1 argument, 0 provided
C:\Users\User\CLionProjects\ex2.2\dummy.h:11:7: note: candidate: 'constexpr Dummy::Dummy(const Dummy&)'
 class Dummy {
       ^~~~~
C:\Users\User\CLionProjects\ex2.2\dummy.h:11:7: note:   candidate expects 1 argument, 0 provided
mingw32-make.exe[3]: *** [CMakeFiles\exe_name.dir\build.make:81: CMakeFiles/exe_name.dir/main.cpp.obj] Error 1
mingw32-make.exe[3]: *** Waiting for unfinished jobs....
mingw32-make.exe[2]: *** [CMakeFiles\Makefile2:94: CMakeFiles/exe_name.dir/all] Error 2
mingw32-make.exe[1]: *** [CMakeFiles\Makefile2:101: CMakeFiles/exe_name.dir/rule] Error 2
mingw32-make.exe: *** [Makefile:136: exe_name] Error 2
SpaceNugget
  • 139
  • 1
  • 11
  • Please [edit] your question to copy-paste the *full* and *complete* build output. Also please add comments on the lines in the shown code where you get the errors. And if possible, please try to make a [mcve] to show us which replicates the error, and nothing more. – Some programmer dude Jun 08 '21 at 11:52
  • On an unrelated note, while [`using namespace std;` is a bad habit](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice) in normal source files, in a header file it's a magnitude worse. – Some programmer dude Jun 08 '21 at 11:53
  • By the way, your `LinkedList(T value)` constructor will dereference `head` when `head` is *uninitialized*. – Some programmer dude Jun 08 '21 at 12:04
  • How can I fix this? >. – SpaceNugget Jun 08 '21 at 12:10
  • A side question: what value of `head` should we expect in the assignment instruction `head->data = value;` at the beginning of `LinkedList(T value)` constructor...? – CiaPan Jun 08 '21 at 12:32
  • The value T provides – SpaceNugget Jun 08 '21 at 13:10
  • T is a type, and I can't see how it provides any value to `head` – there is no initializer at the member declaration, in an initializer list of the ctor declaration nor any assignment. The member seem uninitialized; – CiaPan Jun 08 '21 at 14:32

1 Answers1

2

Ok, so this is a fun one. Have a look here:

template <class T>
class LinkedList {
    struct Node {
        T data; // Here you create a T

When you create a T in node, how do you do it? Well you have to call its constructor. Now lets look at your Dummy. It doesn't have a default constructor, you must call it with Dummy(int). So therefore in Node your T which is now Dummy must be constructed with this constructor. But how!?

That is the conundrum presented by you to your compiler. The compiler has answered, in a strange but sensible way. I can't construct this Node because the default constructor is deleted. It is deleted because its T (Dummy) cannot be default constructed.

A potential fix for this is to add a new constructor to Node, one that takes and copies a T, aka:

struct Node {
    Node(const T &in) : data(in) {}
    T data;

You should experiment with this a little.


A little side note. You have an issue. Think about how you add subsequent nodes,, vs when you construct the first one. Your constructor LinkedList(T value) { has undefined behaviour because it dereferences a null pointer.

Fantastic Mr Fox
  • 32,495
  • 27
  • 95
  • 175
  • This is a great answer but! It is part of my homework to create a SortedList and I cannot assume that my T will have an argument-less constructor. My dummy is just to check how will it work. How can I overcome this? Without adding anything to the dummy (because as I said I can not assume anything about it) – SpaceNugget Jun 08 '21 at 12:02
  • 1
    @SpaceNugget so you cannot assume the items will have a default constructor? In that case you need to have a look at how [`std::list::emplace`](https://en.cppreference.com/w/cpp/container/list/emplace) works. – Fantastic Mr Fox Jun 08 '21 at 12:04
  • 1
    @SpaceNugget Use the solution suggested here, and in your `LinkedList::add` function use `new Node(value)`. The data in the node will no longer need to be default constructed. – Some programmer dude Jun 08 '21 at 12:06
  • @SpaceNugget • You may have missed the *A potential fix for this is...* part of the answer. Another alternative: `struct Node { std::unique_ptr data; Node* next; };` or if something else owns the object `struct Node { T* data; Node* next; };` – Eljay Jun 08 '21 at 12:07
  • 1
    @Someprogrammerdude but it will need to be copy constructed, hopefully that is something that can be assumed about the user of this data structure ... – Fantastic Mr Fox Jun 08 '21 at 12:07
  • I can not assume ANYTHING about class T, but the fix @Someprogrammerdude suggested helped! – SpaceNugget Jun 08 '21 at 12:13
  • @SpaceNugget You have to assume `T` is constructible and destructible otherwise it isn't possible to have a container of `T` values. In C++ you will basically never be able to assume *nothing* about a type. – François Andrieux Jun 08 '21 at 13:38
  • @SpaceNugget • these kinds of little gotchyas are why making really good industrial strength template containers and template smart pointers, such as in the standard C++ library itself, and in Boost, so difficult. There are a lot of nuances and subtle details, and even the luminaries make mistakes. (Even Alexander Stepanov made some mistakes in STL, which Sean Parent has pointed out in some of Sean's talks (with Alexander's approval; he can take the ribbing).) – Eljay Jun 08 '21 at 15:14