2014-12-03 4 views
0

Я пишу класс, который будет служить контейнером для односвязного списка для объектов Student (пользовательский класс, спецификация которого не имеет значения). Он отлично работает (я могу легко добавлять и удалять узлы), за исключением конструктора копирования. С моим конструктором копирования я стараюсь скопировать только данные списка (т. Е. Не сами указатели), но по какой-то причине он segfaults.Segfault on Copy Constructor LinkedList

Ниже приведен соответствующий код (Аннотированный с комментариями объяснить неоднозначные части):

LinkedList::LinkedList(const LinkedList& copy) { 
    Student s = copy.head->getStudent(); 
    //Node can be initialized with a Student pointer argument 
    head = new Node(new Student(s.getFirstName(), s.getMiddleInitial(),s.getLastName(),s.getSSN(),s.getAge())); 
    Node *curr = copy.head->getNext(); 
    Node* prev = head; //For saving the tail 
    while(curr != NULL){ 
     Student s = curr->getStudent(); 
     append(s); 
     prev = curr; 
     curr = curr->getNext(); 
    } 
    tail = prev; 
    cout << "Leaving method..." << endl; 
} 


//Irrelevant methods omitted 
void LinkedList::append(Node*& n) { 
    cout << "Got to appending to node obj" << endl; 
    if (head == NULL) { 
     head = tail = n; 
    } else { 
     tail->setNext(n); 
     tail = tail->getNext(); 
    } 
} 

void LinkedList::append(Student s) { 
    Node* n = new Node(s.getFirstName(),s.getMiddleInitial(),s.getLastName(),s.getSSN(),s.getAge()); 
    append(n); 
} 
//From Node.cpp 
void Node::setNext(Node* _next) { 
    next = _next; //Next is a Node pointer (i.e. Node*) 
} 

Я хотел бы подчеркнуть, что этот код работает отлично, при добавлении к исходному списку. Только во время конструктора копирования этот код выходит из строя. Я побежал этот код через Valgrind и я получаю следующее сообщение об ошибке:

==23990== Invalid write of size 8 
==23990== at 0x403018: Node::setNext(Node*) (Node.cpp:86) //This is the "next = _next" line 
==23990== by 0x402694: LinkedList::append(Node*&) (LinkedList.cpp:81) 
==23990== by 0x402371: LinkedList::append(Student) (LinkedList.cpp:90) 
==23990== by 0x401F68: LinkedList::LinkedList(LinkedList const&) (LinkedList.cpp:31) 

Это меня смущает, как указатель (и должно быть) размером 8, будучи сохраненный указатель (который является размером 8).

Что именно является причиной segfault? Почему этот код выходит из строя во время конструктора копирования, но не при вызове иначе?

+0

Это не размер недопустимой записи, а скорее запись (размером 8), которая недействительна. Похоже, что 'tail' может быть недействительным (это объект, который вы передаете' append') - вы уверены, что он правильно инициализирован? – Cameron

+1

Вам не хватает значительного кода. Взгляните на [MCVE] (https://stackoverflow.com/help/mcve). – Deduplicator

+0

@Cameron Можете ли вы объяснить, что может привести к тому, что запись будет недействительной? Даже если только в общем случае. – ahjohnston25

ответ

1

Я думаю, что вы более усложняя его, вы можете просто сделать это в то время цикла:

LinkedList::LinkedList(const LinkedList& copy) { 
    Student s = copy.head->getStudent(); 
//Node can be initialized with a Student pointer argument 
    head = new Node(new Student(s.getFirstName(),s.getMiddleInitial(),s.getLastName(),s.getSSN(),s.getAge())); 
    Node *curr = copy.head->getNext(); 
    Node *newListCur = head; 
    Node* prev = head; //For saving the tail 
    while(curr != NULL){ 
    Student s = curr->getStudent(); 
    //important step 
    Node* newNode = new Node(new Student(s.getFirstName(),s.getMiddleInitial(),s.getLastName(),s.getSSN(),s.getAge())); 
    newListCur->setNext(newNode); 
    // 
    newListCur = newListCur->getNext(); 
    curr= curr->getNext(); 
    } 
    cout << "Leaving method..." << endl; 
} 

Это не проверяет NULL головок, хотя, так что вы, возможно, придется добавить, что логика

+0

Спасибо. Это работает без segfault. – user3288091

+0

Нет проблем с удовольствием: D – Jay