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

时间:2010-11-07 14:35:18

标签: c++ linked-list

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

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

我不明白为什么它也会调用list类析构函数,并想知道是否有人可以告诉我,以及我应该如何修复它。

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

主要

#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;
}

2 个答案:

答案 0 :(得分:3)

您的函数void list_print(ostream& os, sorted_list list)副本需要sorted_list个参数。一个快速而肮脏的修复(出于性能原因你应该做的)如下:

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

现在,您的iteratorn类采用可变列表,因此这不会按预期工作。您可以通过多种方法进行更改以实现此功能。

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

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

更改签名:

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迭代器接口。

答案 1 :(得分:1)

您按值复制列表,因此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()里面用const_iteratorn返回的起始迭代器初始化sorted_list,副本:

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