2016-10-19 2 views
0

Я пытаюсь понять, почему я получаю seg-ошибку из моей реализации, связанной с одиночным списком.Единственный связанный список - ошибка сегментации из-за реализации Destructor

Я создаю объект типа Deque, называемый dq1, компилятор вызывает деструктор для него, так как программа выполнена - деструктор вызывает remove_front(), который имеет дело с некоторым движением() для головы. Я считаю, что в этом проблема, но я не могу понять, где именно.

Информация отладчика - Не знаете, что с этим делать?

#0 0x4013ea std::unique_ptr<Node, std::default_delete<Node> >::get(this=0x8) (/usr/include/c++/6/bits/unique_ptr.h:305) 
#1 0x401586 std::unique_ptr<Node, std::default_delete<Node> >::operator bool(this=0x8) (/usr/include/c++/6/bits/unique_ptr.h:319) 
#2 0x40140b std::operator!=<Node, std::default_delete<Node> >(std::unique_ptr<Node, std::default_delete<Node> > const&, decltype(nullptr))(__x=<error reading variable: Cannot access memory at address 0x8>) (/usr/include/c++/6/bits/unique_ptr.h:670) 
#3 0x401132 Deque::size(this=0x7fffffffe520) (Deque.cpp:75) 
#4 0x4010f2 Deque::empty(this=0x7fffffffe520) (Deque.cpp:66) 
#5 0x4016dd main() (/test.cpp:12) 

Deque.cpp

#include "Deque.h" 
#include <iostream> 
#include <memory> 
#include <utility> 
#include <stdexcept> 

using std::cout; 
using std::endl; 
using std::move; 

Deque::~Deque() 
{ 
    while (!empty()) remove_front(); 
} 


void Deque::insert_front(int a) 
{ 
    std::unique_ptr<Node> new_node; 
    new_node->val = move(a); 
    new_node->next = move(head); // head is wiped. 
    head = move(new_node); //head is init. with new_node val*/ 
} 


int Deque::remove_front() 
{ 
    if (empty()) {throw std::runtime_error(std::string("Empty"));}; 

    std::unique_ptr<Node> old; 
    int return_value = head->val; 
    old = move(head); 
    head = move(old->next); 
    delete &old; 
    return return_value; 
} 


bool Deque::empty() const 
{ 
return (size() == 0); 
} 
int Deque::size() const 
{ 

int size_val = 0; 
const Node* p = head.get(); 

while (p != NULL) 
    { 
     size_val++; 
     p = p->next.get(); 
    } 
    return size_val; 
} 

test.cpp

#include <iostream> 
#include "Deque.h" 



using std::cout; 
using std::endl; 

int main() 
{ 

    Deque dq1; 
     return 0; 
} 

deque.h

#include "Node.h" 
#include <memory> 

class Deque{ 
    public: 
     Deque() = default; 
     Deque(const Deque&); 
     ~Deque(); //must use constant space 
     Deque& operator=(const Deque&){return *this;}; 
     void insert_front(int); 
     int remove_front(); 
     bool empty() const; 

    private: 
    friend Node; 
     std::unique_ptr<Node> head ; 
     std::unique_ptr<Node> tail ; 

}; 

node.h

#include "Node.h" 

std::ostream& operator<<(std::ostream& out, const Node& n) { 
    return out << &n << ": " << n.val << " -> " << n.next.get(); 
} 
+0

Вы должны ** никогда ** не называть 'delete' на указатель, принадлежащий' std :: unique_pointer'. Проверьте реализацию 'int Deque :: remove_front()' в вашем * Deque.cpp * – WhiZTiM

+0

. Тогда как деструктор освобождает память, используемую уникальным указателем? – TigerCode

+0

@TigerCode http://en.cppreference.com/w/cpp/memory/unique_ptr – GMichael

ответ

1

Вы UB прямо здесь:

std::unique_ptr<Node> new_node; 
new_node->val = move(a); 

создать новый указатель, который по умолчанию инициализируется (указывает на nullptr), и вы разыменования его. Вы должны инициализировать его с std::make_unique, если у вас есть C++ 14 или более поздней версии, или просто инициализировать его с new:

std::unique_ptr<Node> new_node = std::make_unique<Node>(); // C++14 or later 
std::unique_ptr<Node> new_node(new Node); // pre C++14 

Эта линия также имеет вопрос:

delete &old; 

эта линия не имеет никакого смысла. Вы получаете адрес самого указателя, который создается как локальная переменная и пытается удалить его. Если вы попытались удалить данные, на которые указывает old, то это не так. Это целая точка std::unique_ptr, чтобы сделать это автоматически.

Этот элемент:

std::unique_ptr<Node> tail ; 

это неправильно дизайн, хотя вы, кажется, не использовать его в коде. Предполагается, что у вас будет несколько std::unique_ptr, чтобы указать на один и тот же объект. Но этот указатель предназначен для уникальной собственности.

У вас, кажется, есть проблема в Deque::size(), но, не видя источника, невозможно сказать, что там не так.

В вашем деструкторе вам не нужно ничего делать (хотя это не повредит, если другие методы будут реализованы должным образом) - std::unqiue_ptr уничтожит все данные рекурсивно.

+0

Я забыл включить размер() в сообщение - я включил его сейчас. То, где мой отладчик привел меня. @Slava – TigerCode

+0

Я полагаю, что это связано с тем, как я создал указатель на узле P – TigerCode

+0

@TigerCode 'size()' выглядит нормально, кажется, что проблема использования 'nullptr' в' insert_front() 'прерывает его. – Slava