您好 我有一些关于构造函数和析构函数的问题。我有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);
}
#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;
}
#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
#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;
}
#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;
}
答案 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。