单向链表 - 由于析构函数的实现而导致的分段错误
Singly Linked List - Segmentation Error due to Destructor implementation
我想弄清楚为什么我的单向链表实现会出现段错误。
我创建了一个名为 dq1 的 Deque 类型的对象,编译器在程序完成后为其调用析构函数 - 析构函数调用 remove_front() 处理头部的一些 move()。我相信这就是问题所在,但我似乎无法弄清楚它到底在哪里。
调试器信息 - 不知道该怎么做?
#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();
}
你有 UB:
std::unique_ptr<Node> new_node;
new_node->val = move(a);
您创建了一个默认初始化的新指针(指向 nullptr
)并取消引用它。如果你有 C++14 或更高版本,你应该用 std::make_unique
初始化它,或者只用 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
将递归地销毁所有数据。
我想弄清楚为什么我的单向链表实现会出现段错误。
我创建了一个名为 dq1 的 Deque 类型的对象,编译器在程序完成后为其调用析构函数 - 析构函数调用 remove_front() 处理头部的一些 move()。我相信这就是问题所在,但我似乎无法弄清楚它到底在哪里。
调试器信息 - 不知道该怎么做?
#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();
}
你有 UB:
std::unique_ptr<Node> new_node;
new_node->val = move(a);
您创建了一个默认初始化的新指针(指向 nullptr
)并取消引用它。如果你有 C++14 或更高版本,你应该用 std::make_unique
初始化它,或者只用 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
将递归地销毁所有数据。