【问题标题】:Linked list assignment operator链表赋值运算符
【发布时间】:2014-02-08 03:26:49
【问题描述】:

我为链表的重载 = 运算符编写了一些代码,但由于某种原因它没有做任何事情,我不知道为什么。

包含链表的类称为String,结构ListNode是节点本身。

列表节点:

struct ListNode
{
      char info;
      ListNode * next;
      ListNode(char newInfo, ListNode * newNext)
        : info( newInfo ), next( newNext )
      {
      }
};

字符串:

class String {

    private:
        ListNode* head;

    public:
    String( const char * s = "");
    String( const String & s );
    String operator = ( const String & s );
    ~String();
}
ostream & operator << ( ostream & out, String& str );
istream & operator >> ( istream & in, String & str );

字符串.cpp:

String::String( const char * s) {
    if (s == "") {
        head = NULL;
        return;
    }

    ListNode* newNode = new ListNode(s[0], NULL);
    head = newNode;
    ListNode* current = head;
    for (int i = 1; s[i] != 0; current = current->next) {
        current->next = new ListNode(s[i], NULL);
        ++i;
    }
}

String::String(const String& s ) {

    ListNode* current = new ListNode((s.head)->info, NULL); //make all next's null just in case
    head = current;
    for(ListNode* sstart = s.head->next; sstart != NULL; sstart = sstart->next) {
            current->next = new ListNode(sstart->info, NULL);
            current = current->next;
    }

}

//RETURN STRING BY REFERENCE OR COPY CONSTRUCTOR IS CALLED
String& String::operator = ( const String & s ) {
    ListNode* start = head;
    ListNode* tmp;
    while(start != NULL) {
        tmp = start->next;
        delete start;
        start = tmp;
    }

    head = NULL;

    if (s.head == NULL)
        return *this;    
    ListNode* current = new ListNode((s.head)->info, NULL); //make all next's null just in case
    head = current;
    for(ListNode* sstart = s.head->next; sstart != NULL; sstart = sstart->next) {
            current->next = new ListNode(sstart->info, NULL);
            current = current->next;
    }

    return *this;

}

String::~String() {
    ListNode* nextNode = head;
    ListNode* tmp;
    while(nextNode) {
        tmp = nextNode->next;
        delete nextNode;
        nextNode = tmp;
    }
}

ostream & operator << ( ostream & out, String& str) {

    for (int i = 0; i < str.length(); ++i) {
        out << str[i];
    }
    return out;

}

istream & operator >> ( istream & in, String & str ) {
    int len = in.gcount();
    char* buf = new char[len];
    char inChar;
    for(int i = 0; in >> inChar; ++i) {
        buf[i] = inChar;        
    }
    String tmp(buf);
    str = tmp;
}

在第一个循环中,我删除了 head 指向的链表。之后,对于 s 根本不包含任何内容的情况,我将 head 设置为 NULL。如果不是,那么我将 current 设置为 s 中第一个 ListNode 的副本,并将 current 存储在 head 中(如果我使用 head 遍历,那么我会丢失指向列表开头的指针)。最后,我的第二个循环会将 s 的其余部分“附加”到当前。

当我运行我的代码时,什么也没有发生。我的终端会打印出一个空白行,然后什么也没有,这表明我可能会在某个地方无限前进。我的代码有什么问题?

编辑:更改了此链接列表的删除,问题仍然存在。

【问题讨论】:

  • 在这种情况下,您的代码中有一个非常明显的错误。但是,提供一个完整的、可编译的示例通常会更好(尽管并非总是必要的)。通常问题不在您认为的地方。例如,我们假设您实际上(正确地)动态分配内存,因为尽管有 delete,但没有 new
  • 一方面,在第一个循环中,您正在访问已删除的内存(即 delete start 包括删除 start 的“next”指针。应该是“tmp=start->next; delete start; start =tmp;"
  • 下次有一个建议——为你的链表编写原始函数,例如 Add()、Insert()、Remove() 等。然后赋值运算符就变成了一个简单的函数几行。

标签: c++ list


【解决方案1】:

您通过访问已在此代码 sn-p 中删除的对象(因为 tmp == start)导致未定义的行为:

tmp = start;
delete start;
start = tmp->next;

可能还有其他问题,但首先要解决它。例如,您可以在删除之前将 next 指针存储在临时变量中:

tmp = start->next;
delete start;
start = tmp;

【讨论】:

  • 改变了,我仍然有同样的问题。这一次,我很确定这是因为我在某处搞砸了我的第二个 for 循环。编辑:我使用的例子是: String s("Hello");字符串 t("再见"); s = t;
  • @JonathanChiou 几点:我们不知道您是如何实现 String( const char *) 构造函数的,您没有在该 sn-p 中包含任何输出语句,我们不知道如何该类自己写出来,请编辑您的问题并将附加代码放在那里。
  • @JonathanChiou 请阅读stackoverflow.com/help/mcvesscce.org,然后给我们一个有用的例子。您更新的代码更完整,但仍然缺少一些内容并包含一些语法错误。修复了这些,我刷新了类似于我猜你已经完成的代码。 result 确实打印出我所期望的。顺便说一句,至少有一个不相关的语义错误(不要用s==""检查char *构造函数中的空字符串)
【解决方案2】:

我测试了你在问题中的代码,似乎是重载的问题

ostream & operator << ( ostream & out, String& str) {

    ListNode *p = str.head; // change head to public or define a public function get_head;
    while(p)
    {
        out << p->info;
        p = p->next;
    }

    return out;

}

【讨论】:

  • 我确实有一个复制构造函数,但我认为它与我的问题无关。
  • @JonathanChiou,方便你把所有代码都放在问题里吗?
  • 如果您编写了一个复制构造函数,那么为什么不让您的赋值运算符使用复制/交换习语调用复制构造函数呢?否则你只是在复制代码。
  • 假设您确实编写了一个复制构造函数并对其进行了彻底的测试,下面是描述的复制/交换习惯用法:stackoverflow.com/questions/3279543/… 使用这个习惯用法,您不再需要在赋值运算符。
猜你喜欢
  • 2015-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-02
  • 1970-01-01
  • 2018-11-13
  • 2016-02-24
  • 2011-08-02
相关资源
最近更新 更多