0

I'm doing some exercises from the book "think like a programmer" and everything has been great so far. I started the classes chapter and here I seem to be stuck as I can't wrap my head around the error I'm getting compiling the code.

Here is the code. It is not mine, I have been writing it along the book trying to understand it.

struct studentRecord {
    int studentId;
    int grade;
    string name;
    studentRecord(int a, int b, string c); 
};

class studentCollection {
  private:
    struct studentNode {
        studentRecord studentData;
        studentNode *next;
    };
  public:
    studentCollection();
    void addRecord(studentRecord newStudent);
    studentRecord recordWithNumber(int idNum);
    void removeRecord(int idNum);
  private:
    //typedef studentNode *studentList;
    studentNode *_listHead;
};

studentRecord::studentRecord(int a, int b, string c) {
    studentId = a;
    grade = b;
    name = c;
}

studentCollection::studentCollection() {
    _listHead = NULL;
}


void studentCollection::addRecord(studentRecord newStudent) {
    studentNode *newNode = new studentNode;
    newNode->studentData = newStudent;
    newNode->next = _listHead;
    _listHead = newNode;
}

studentRecord studentCollection::recordWithNumber(int idNum) {
    studentNode *loopPtr = _listHead;
    while (loopPtr != NULL && loopPtr->studentData.studentId != idNum) {
        loopPtr = loopPtr->next;
    }
    if (loopPtr == NULL) {
        studentRecord dummyRecord(-1, -1, "");
        return dummyRecord;
    } else {
        return loopPtr->studentData;
    }
}

int main() { 
    studentCollection s;
    studentRecord stu3(84, 1152, "Sue");
    studentRecord stu2(75, 4875, "Ed");
    studentRecord stu1(98, 2938, "Todd");
    s.addRecord(stu3);
    s.addRecord(stu2);
    s.addRecord(stu1);
}

The error I'm getting is:

studentclass1.cpp: In member function ‘void studentCollection::addRecord(studentRecord)’:
studentclass1.cpp:45:32: error: use of deleted function ‘studentCollection::studentNode::studentNode()’
     studentNode *newNode = new studentNode;
                                ^~~~~~~~~~~
studentclass1.cpp:17:12: note: ‘studentCollection::studentNode::studentNode()’ is implicitly deleted because the default definition would be ill-formed:
     struct studentNode {
            ^~~~~~~~~~~
studentclass1.cpp:17:12: error: no matching function for call to ‘studentRecord::studentRecord()’
msaitz
  • 35
  • 2
  • 7
  • 3
    If this book is really teaching you to use raw owning pointers and leaking memory you should throw it away and [get a better book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – nwp Apr 17 '17 at 18:40
  • 1
    Why do you, and so many other people posting here, find it so difficult to post the actual code, complete with preprocessor directives? –  Apr 17 '17 at 18:45
  • Use `nullptr` instead of `NULL` – Guillaume Racicot Apr 17 '17 at 18:46
  • @Gill `studentNode` is declared within `studentCollection` – zett42 Apr 17 '17 at 18:46
  • *think like a programmer* -- If you did that, you would have used `std::list` and got yourself actually writing a student record system, instead of this thing disguised as a home-made linked list. – PaulMcKenzie Apr 17 '17 at 18:48
  • @nwp Well, I believe that the code pasted here is an ongoing exercise where there must me wrong stuff to make the readers figure out what's failing or can be improved. At least it's been like that till this point of the book. – msaitz Apr 17 '17 at 18:50
  • @NeilButterworth It's the first time I've been in the need of asking here. Should I include it from now on? – msaitz Apr 17 '17 at 18:52
  • 1
    Yes. How a C++ program functions is complete;ly dependent on the header files it includes. –  Apr 17 '17 at 18:54
  • @msaitz -- *to make the readers figure out what's failing or can be improved* -- How is a beginner supposed to know about the "rule of 3", proper memory management, etc. unless it is demonstrated to them first? Also, there is a good chance that buggy code will **not** fail, thus giving the beginner the false sense that their code is ok. – PaulMcKenzie Apr 17 '17 at 18:55
  • @PaulMcKenzie I see your point, but I must say that this code is part of the chapter's introduction and is not an actual exercise. The author does explain the code and after that he does go through it several times pointing out what can go wrong with it and the strategies for improving it. Having said that, it's the first book I grab and and I'm sure I may be missing if the author is not teaching something right. – msaitz Apr 17 '17 at 19:02

3 Answers3

4

When you define a struct such as:

struct studentNode {
    studentRecord studentData;
    studentNode *next;
};

it has an implicitly defined default constructor that is equivalent to:

struct studentNode {
    studentNode() : studentData(), next() {}
    studentRecord studentData;
    studentNode *next;
};

That is a problem since the default constructor of studentRecord is deleted by the compiler due to the presence of a user defined constructor.

You can add a default constructor to studentRecord to get over that problem.

struct studentRecord {
    int studentId;
    int grade;
    string name;
    studentRecord() = default; 
    studentRecord(int a, int b, string c); 
};

Instead of using the computer generated default constructor with the = default; specifier, it will be better to initialize the object with valid data.

struct studentRecord {
    int studentId;
    int grade;
    string name;
    studentRecord() : studentRecord(0, 0, "") {} // Delegate to the other constructor. 
    studentRecord(int a, int b, string c); 
};
user4581301
  • 33,082
  • 7
  • 33
  • 54
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • A default-constructor like this would be error-prone as it doesn't initialize members `studentId` and `grade`. – zett42 Apr 17 '17 at 18:44
  • The compiler generated compiler doesn't actually default initialize `studentData` and `next` though. – Hatted Rooster Apr 17 '17 at 18:51
  • @GillBates, you are most likely right. I have not been able to grok the entirety of initialization of objects. – R Sahu Apr 17 '17 at 19:06
2

studentRecord is not default constructible because you have provided a user constructor (studentRecord(int a, int b, string c);). Therefore studentNode cannot have a compiler-generated default constructor. Provide one for it yourself or give studentRecord a default constructor.

AndyG
  • 39,700
  • 8
  • 109
  • 143
1

The structure studentRecord has a user-define constructor

struct studentRecord {
    int studentId;
    int grade;
    string name;
    studentRecord(int a, int b, string c); 
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
};

In this case the compiler does not generate the default constructor for the structure.

At the same time inside the function addRecord

void studentCollection::addRecord(studentRecord newStudent) {
    studentNode *newNode = new studentNode;
                           ^^^^^^^^^^^^^^^^
    newNode->studentData = newStudent;
    newNode->next = _listHead;
    _listHead = newNode;
}

there is an attempt to use the default constructor of the structure studentRecord. As it can not be used the compiler defined the default constructor of the structure studentNode as deleted.

You can avoid the error by explicitly providing the initializer for the data member studentRecord studentData and using the aggregate initialization

The function can be written the following way

void studentCollection::addRecord(studentRecord newStudent) {
    studentNode *newNode = new studentNode { newStudent, _listHead };
    _listHead = newNode;
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335