构造函数和析构函数的链表问题

Posted

技术标签:

【中文标题】构造函数和析构函数的链表问题【英文标题】:Linked list problem with constructor and destructor 【发布时间】:2010-11-07 14:35:17 【问题描述】:

嗨 我有一些关于构造函数和析构函数的问题。我有一个列表类,它有两个内部类,一个用于列表节点的私有类和一个公共迭代器类。

现在针对这个问题,我编写了一个使用内部迭代器类的非成员打印函数。当我使用这个非成员函数时,它将结束调用迭代器的析构函数。但它并没有在这里结束,因为出于某种原因它也会调用列表类的析构函数。当我想再次打印列表内容时,这会导致一些问题。

我不明白为什么它也调用列表类析构函数,想知道是否有人可以告诉我,以及我应该如何解决它。

我已经附上了与问题相关的所有代码

主要

#include <iostream>

#include "sorted_list.h"
#include "iterator.h"
using namespace std;

void list_print(ostream& os, sorted_list list)

    sorted_list::iteratorn it(&list);

    while( ! it.iterator_end())
    
        os <<   "key = " << setw(3) << it.iterator_get_key()   << ", "
        << "value = " << setw(5) << it.iterator_get_value() << endl;
        it.iterator_next();
    

    os << endl;


int main()



    sorted_list a;
    a.insert(4,4);
    a.insert(5,5);


    list_print(cout,a);
    list_print(cout,a);

sorted_list.cc

#include "sorted_list.h"

sorted_list::sorted_list()

    cout << "construct sorted_list" << endl;
    this->first = 0;

sorted_list::~sorted_list()

    cout << "destruct sorted_list" << endl;
    destroy(this->first);



void sorted_list::destroy(list_link* item)

    cout << "destroy list_link" << endl;
    if(item)
    
        destroy(item->next);
        delete item;
    



void sorted_list::insert(int key, double value)

    list_link *curr;
    list_link *prev = 0;

    curr = first;

    while(curr)
    
        if(value < curr->value)
            break;

        prev = curr;
        curr = curr->next;
    
    if(this->first == 0 || prev == 0) //if empty or add first
    
        //first = create(key, value, this->first);
        first = new list_link(key, value, this->first);
    
    else if(curr == 0)
    
        //prev->next = create(key, value, 0);
        prev->next = new list_link(key, value, 0);
    
    else
    
        //prev->next = create(key, value, curr);
        prev->next = new list_link(key, value, curr);
    


void sorted_list::remove(my_key_type key)

    list_link *curr = first;;
    list_link *prev = 0;

   while(curr)
   
      if(curr->key == key)
      
         list_link *remove;

         if(prev == 0)
         
            first = curr->next;
            delete curr;
            curr = first;
         
         else
         
            remove = curr;
            curr = curr->next;
            prev->next = curr;
            delete remove;
         
         continue;
      
      prev = curr;
      curr = curr->next;
   



sorted_list::list_link* sorted_list::clone(list_link* item)

   list_link* copyItem= new list_link(item->key,item->value,0);
   if(item->next!= 0)

      copyItem->next=clone(item->next);
   return copyItem;
    // ADD YOUR CODE HERE ( 4 well formatted lines in reference solution )



void sorted_list::copy(sorted_list* my_this_destination)

  if (my_this_destination->first == 0) // copy if empty
  
      cout << "Copy" << endl;
    //list_destroy(my_this_destination);
    my_this_destination->first = clone(first);
  


double sorted_list::find(int key)

    list_link *travel = this->first;
    while(travel)
    
        cout << travel->key << "==" << key << endl;
        if(travel->key == key)
            return travel->key;

        travel = travel->next;
    
    return -1;


int sorted_list::size()

    list_link *travel = this->first;
    int i = 0;
    while( travel )
    
        travel = travel->next;
        i++;
    
    return i;

sorted_list.h

#ifndef _SORTED_LIST_H_
#define _SORTED_LIST_H_

#include <iostream>

#include <iomanip>
using namespace std;

typedef int     my_key_type;
typedef double  my_value_type;

class sorted_list


public:
    sorted_list(); 
    ~sorted_list();

    void insert(int key, double value);
    void remove(my_key_type key);
    void copy(sorted_list* my_this_destination);
    void destroy();
    void init(struct my_list* my_this);
    void print();
    void print2();
    double find(int key);
    int  size();

private:
    class list_link // An inner class inside sorted_list
    
    public:
        list_link (my_key_type key, my_value_type value, list_link* next = 0);
        ~list_link();
        my_key_type key;
        my_value_type value;
        list_link *next;
    ;

    list_link* first;
    list_link* clone(list_link* item);
    void destroy(list_link* item);
    // More declarations

public:
    class iteratorn
    
    public:
        iteratorn();
        ~iteratorn();
        iteratorn(sorted_list *item);
        list_link* list_begin();
        bool iterator_end();
        void iterator_next();
        int iterator_get_key();
        double iterator_get_value();

    private:
        sorted_list::list_link* current;
    ;
;


#endif

iteratorn.cc

#include "iterator.h"
#include "sorted_list.h"

 sorted_list::iteratorn::iteratorn()
 
 
sorted_list::iteratorn::iteratorn(sorted_list *list)

    cout << "construct iteratorn" << endl;
    this->current = list->first;


sorted_list::iteratorn::~iteratorn()

    cout << "destruct iteratorn" << endl;


sorted_list::list_link* sorted_list::iteratorn::list_begin()

    return current;


void sorted_list::iteratorn::iterator_next()

  current = current->next;


int sorted_list::iteratorn::iterator_get_key()

  return current->key;


double sorted_list::iteratorn::iterator_get_value()

  return current->value;

list_link.cc

#include "sorted_list.h"


sorted_list::list_link::list_link(my_key_type key, my_value_type value, list_link* next)

    this->key = key;
    this->value = value;
    this->next = next;


sorted_list::list_link::~list_link()

    cout << "list_link destructor" << endl;

【问题讨论】:

代码太多。您是否尝试过使用调试器并单步执行代码以查看究竟发生了什么?试试这个,然后问一个更具体的问题。 您在这种情况下对“迭代器”的使用在 C++ 中是不合适的。请使用正确的术语以避免混淆。 @Space_C0wb0y 不请自来,上次是很少的代码。好吧,如果您不打算提供帮助,至少您不需要评论 @starcorn:艺术就是发布相关代码。不多不少。 @starcom:虽然 Space_C0wb0y 的评论表达得不好,但发布一个重现问题的最小程序通常会 1)帮助你发现错误并学习一些东西; 2) 吸引同情和帮助,因为这表明您确实尝试过某事(#1)并且有一个更有趣的问题要问。 【参考方案1】:

您的函数void list_print(ostream&amp; os, sorted_list list) 通过复制获取sorted_list 参数。一个快速而肮脏的修复(出于性能原因,无论如何你都应该这样做)如下:

void list_print(ostream& os, const sorted_list& list)

现在,您的 iteratornclass 采用 可变 列表,因此这不会像您预期的那样工作。您将有很多方法可以更改以完成这项工作。

无论如何,你真正的问题是缺少合适的复制构造函数。现在,当你“复制”一个列表时,两者最终共享相同的元素,但你的析构函数被编写为好像每个列表都拥有它自己的节点。定义正确的复制操作,它将解决您的问题。

关于如何解决问题的详细帮助:(未经测试)

更改签名:

void list_print(ostream& os, const sorted_list& list);

声明+定义复制构造函数:

sorted_list::sorted_list (const sorted_list& other);

更改iteratorn 接口以支持const sorted_list

class sorted_list::iteratorn

public:
    iteratorn();
    ~iteratorn();
    iteratorn(const sorted_list& list);
    const list_link* list_begin() const;
    bool iterator_end() const;
    void iterator_next();
    int iterator_get_key() const;
    double iterator_get_value() const;

private:
        // You *should* make this `const` but it is not required.
    sorted_list::list_link* current;
;

如您所见,更改相当小,但需要在不同的地方应用。

const + 非const 迭代器

我在此处应用更改是基于您的 iteratorn 当前仅在您的 sorted_list 上定义只读操作。如果您想支持写访问以允许更改存储在列表节点中的值(从不 允许更改键,否则您将不再有 排序 列表),您应该定义两个迭代器类。有关详细信息,请参阅 STL 迭代器接口。

【讨论】:

是我需要为 iteratorn 类或 sorted_list 编写一个复制构造函数吗? 列表拥有项目,而不是迭代器。所以你需要一个sorted_list的拷贝构造函数! 快速修复解决了问题。但由于这是一个肮脏的修复,我想通过使用复制构造函数来解决这个问题。我在 sorted_list 中编写了一个复制构造函数。当我现在调用迭代器时,它会在运行析构函数之后立即使用复制构造,然后迭代器可以对其进行任何操作。我不知道是不是因为我编写了一个单独的函数来进行复制,而不是在复制构造函数中完成所有操作。 迭代器可能仍应使用指向sorted_list 的指针,就像在原始代码中一样(尽管需要const 指针)。如果我正确理解您的评论,则您已通过副本将列表传递给迭代器。由于评论格式有限,我将编辑我的答案以更清楚地解释它。【参考方案2】:

您正在按值复制列表,因此list_print() 中的本地副本在范围结束时会破坏。改为通过 const-reference 传递它。

这反过来意味着您必须更改您的 sorted_list 以支持使用 const 列表。特别是你需要有一个函数返回一个指向列表开头的 const 迭代器:

sorted_list::const_iteratorn begin() const

    // returns a const_iteratorn pointing at the beginning of this list

请注意,您需要一种新的迭代器:const_iteratorn,它保证不会更改列表。

然后,在 print_list() 内部使用 sorted_list 返回的起始迭代器初始化一个 const_iteratorn,复制:

sorted_list::const_iteratorn s(list.begin());

最后创建第二个迭代器实例,该实例使用来自sorted_list 的成员函数的结束迭代器进行初始化,类似于begin() 函数。这将保持print_list() 中的常量正确性。

sorted_list::const_iteratorn e(list.end());
while( s != e )        // two iterators should be able to compare
    // ...
    s.iterator_next();  // consider ++s

此外,正如 André 所提到的,您没有适当的复制构造函数和赋值运算符这一事实是一个严重的问题。确保复制sorted_list 意味着复制其所有元素,以便新对象拥有自己的元素列表。记得Rule of Three。

【讨论】:

以上是关于构造函数和析构函数的链表问题的主要内容,如果未能解决你的问题,请参考以下文章

php构造函数的PHP 5 构造函数和析构函数

构造函数和析构函数能不能被继承

构造函数和析构函数

5 规则(用于构造函数和析构函数)过时了吗?

对于默认构造函数和析构函数,“=default”与“”有何不同?

c++中的构造函数和析构函数