【问题标题】:operator= on pointers possibly causing a segmentation fault on macoperator= on 指针可能导致mac上的分段错误
【发布时间】:2016-11-04 16:48:39
【问题描述】:

我正在尝试编写一个带有链表的类 Set 来存储整数。在我的 Mac 终端上编译并运行后,输出如下:

[]
[10]
[10, 20]
Segmentation fault: 11

但我期待看到以下输出:

[]
[10]
[10, 20]
[10, 20]
[10, 20, 30]

我想知道是不是我的 operator= 函数有问题,还是我不能将 operator= 函数与指针一起使用?如果是这样,我应该如何纠正问题以使程序按预期输出?我真的很感谢你的帮助。提前致谢!

#include <iostream>
using namespace std;

class Node {
  public:
    int value;
    Node* next;
    Node(int n, Node* ptr = NULL) : value(n), next(ptr) {}
};

class Set {
  Node* head;
  friend ostream& operator<<(ostream&, const Set&);
  public:
    Set() : head(NULL) {}
    Set(const Set& another){ *this = another; }
    ~Set();
    Set& operator+=(const int&);
    Set& operator=(const Set&);
};

int main() {
    int num1 = 10;
    int num2 = 20;
    int num3 = 30;
    Set set1;
    cout << set1;
    Set* set2;
    set1 += num1;
    cout << set1;
    set1 += num2;
    cout << set1;
    set2 = new Set(set1);
    cout << *set2;
    *set2 += num3;
    cout << *set2;
    delete set2;
    return 0;
}

Set::~Set() {
    Node* current = head;
    while (current != NULL) {
        Node* temp = current;
        current = current->next;
        delete temp;
    }
}

Set& Set::operator+=(const int& aNum) {
    if (head == NULL) {
        head = new Node(aNum);
        return *this;
    }
    Node* previous = head;
    Node* current = head->next;
    while (current != NULL) {
        previous = current;
        current = current->next;
    }
    previous->next = new Node(aNum);
    return *this;
}

Set& Set::operator=(const Set& another) {
    if (this != &another) {
        Node* current = head;
        while (current != NULL) {
            Node* temp = current;
            current = current->next;
            delete temp;
        }
        Node* anotherCurrent = another.head;
        while (anotherCurrent != NULL) {
            *this += anotherCurrent->value;
            anotherCurrent = anotherCurrent->next;
        }
    }
    return *this;
}

ostream& operator<<(ostream& os, const Set& s) {
    os << "[";
    for (Node* p = s.head; p != NULL; p = p->next) {
        os << p->value;
        if (p->next != NULL)
            os << ", ";
    }
    os << "]" << endl;
    return os;
}

【问题讨论】:

  • 调试器是解决此类问题的正确工具。 询问 Stack Overflow 之前,您应该逐行浏览您的代码。如需更多帮助,请阅读How to debug small programs (by Eric Lippert)。至少,您应该 [编辑] 您的问题,以包含一个重现您的问题的 Minimal, Complete, and Verifiable 示例,以及您在调试器中所做的观察。
  • Set(const Set&amp; another){ *this = another; } -- 这不是编写复制构造函数的好方法。您应该在没有赋值运算符帮助的情况下编写复制构造函数(假设赋值操作不存在)。然后,一旦你这样做了,编写赋值运算符就变成了一个 2 行函数。
  • @PaulMcKenzie 感谢您的帮助。我在不使用赋值运算符的情况下重写了复制构造函数并且它起作用了。但是,我不知道为什么复制构造函数不能使用赋值运算符?另外,赋值运算符应该如何使用复制构造函数编写?非常感谢^
  • @πάνταῥεῖ 感谢您的回复。我在 Xcode 上运行代码没有问题,只有在终端运行时才会出现问题。此外,我实际上正在处理一个更大的项目,其中包含更多的头文件。在发布之前,我实际上是从头开始编写代码,只包含产生相同输出的必要函数,以及我认为导致问题的函数。我提供的 main() 也只是测试功能的示例。无论如何,谢谢,我一定会为您提供的链接添加书签:)
  • @mlkw - 赋值运算符:{ Set temp(another); std::swap(temp.head, head); return *this; } 如果您编写独立于赋值运算符的复制构造函数并确保您的 Set 析构函数正常工作,这就是您需要做的一切。够简单吗?基本上,当您实现规则 3 时,首先从复制构造函数和析构函数开始 - 将赋值运算符放在最后,因为它变得微不足道。

标签: c++ macos terminal segmentation-fault operator-overloading


【解决方案1】:

在复制之前删除之前的列表时,您必须将head 设置为NULL,否则+= 运算符将使用head,并且它当前未分配但不是NULL

Set& Set::operator=(const Set& another) {
    if (this != &another) {
        Node* current = head;
        while (current != NULL) {
            Node* temp = current;
            current = current->next;
            delete temp;
        }
        head = NULL;   // <============== code to add
        Node* anotherCurrent = another.head;
        while (anotherCurrent != NULL) {
            *this += anotherCurrent->value;
            anotherCurrent = anotherCurrent->next;
        }
    }
    return *this;

顺便说一句,一个非常有趣的设计模式,必读:copy-and-swap idiom

【讨论】:

  • 非常感谢您的帮助。我添加了代码行,但问题仍然存在。然而,在不使用赋值运算符的情况下重写复制构造函数就可以了,尽管我不知道为什么。无论如何,谢谢,我一定会阅读您提供的链接 xd
  • @mlkw - 阅读我对您的评论。一旦你改变了复制构造函数,赋值运算符就变成了一个 3 行函数(都是由于使用了复制/交换习惯用法)。
猜你喜欢
  • 1970-01-01
  • 2021-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-02
  • 2013-07-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多