【发布时间】:2010-11-21 14:12:52
【问题描述】:
大家好,菜鸟问题。
所以我有一个实现单链表的模板类。我的程序中的类中的函数返回这些列表之一。
psList<int> psObj::getList() const {
return List;
}
所以发生的事情是在调用返回 List 时复制构造函数启动,它很好地完成了它的工作并创建了列表的副本。然而,函数完成并超出范围并调用析构函数!突然返回的链表被删除,因为这是我的析构函数所做的,删除一个列表并很好地删除它。
我知道我可以将返回类型设置为指向复制列表头部的指针,一切都会很好,但问题是我仍然无法创建返回动态结构副本的函数,即使我想这样做,我也确实想这样做。
有人要求我提供更多代码。
这里是拷贝构造函数,显然是做深拷贝
template<class psClass>
psList<psClass>::psList(const psList &original) {
head = NULL;
if(original.head != NULL) {
psNode<psClass>* iterator = original.head;
while(iterator != NULL) {
pushback(iterator->data);
iterator = iterator->next;
}
}
}
这是析构函数
template<class psClass>
psList<psClass>::~psList() {
erase();
}
这是析构函数调用的擦除函数。
template<class psClass>
void psList<psClass>::erase() {
psNode<psClass>* iterator = head;
psNode<psClass>* buff;
while(iterator != NULL) {
buff = iterator->next;
delete iterator;
iterator = buff;
}
}
所以是的,我正在做深度复制和深度破坏。问题不在于深度。问题是这样的。在原始函数中,制作并返回深层副本。该函数超出范围,并在副本上调用深度析构函数。不再复制。
为了更好地解释这里是调试器中的样子
getlist 函数调用之前的原始列表。
head 0x616080
data 2
next 0x616060
data 12
next 0x0
这是 getList 函数中“返回列表”的列表
head 0x616080
data 2
next 0x616060
data 12
next 0x0
同样的事情。
这里是复制构造函数末尾的“original”和“this”列表。
“这个”
head 0x63c900
data 2
next 0x63a940
data 12
next 0x0
“原创”
head 0x616080
data 2
next 0x616060
data 12
next 0x0
一切看起来都很棒不是吗。
现在我们回到了 getList 函数,即将进入最后一个括号。
psList<int> psObj::getList() const {
return List;
} // This bracket
这个函数后面的列表List就是你所期望的
head 0x616080
data 2
next 0x616060
data 12
next 0x0
现在我们进入最后一个括号,析构函数在哪里被调用
/*
* No idea what the in chrg thing is or why the debugger is telling me it was
* optimized out but I mentioned it here cause maybe it has something to do with my
* problem
*/
this 0x7ffffffe650
__in_chrg value optimized out
// Look familiar? well it should cause it is the head of the list I returned.
head 0x63c900
data 2
next 0x63a940
data 12
next 0x0
然后砰!我刚刚复制并返回的列表被析构函数删除,因为它超出了范围。
在那次绕道之后重申我最初的问题。如何让函数使用深层副本返回动态结构,而不让析构函数破坏所述副本。
应要求提供更多代码
// Simple single link node with default constructor initializing the link to NULL.
template <class psClass>
struct psNode {
psClass data;
psNode<psClass>* next;
psNode() {
next = NULL;
}
};
还有推回功能
template<class psClass>
void psList<psClass>::pushback(psClass object) {
psNode<psClass>* ptr = new psNode<psClass>;
ptr->data = object;
if(head == NULL)
head = ptr;
else {
//Have to find the tail now
psNode<psClass>* tail;
psNode<psClass>* iterator = head;
while(iterator != NULL) {
tail = iterator;
iterator = iterator->next;
}
tail->next = ptr;
}
}
是的,我知道跟踪 tail 会更容易。
这是 psList 类定义:
template <class psClass>
class psList {
public:
psList();
~psList();
psList(const psList &original);
psList(psNode<psClass>* _head);
void erase();
void pushfront(psClass object);
void pushback(psClass object);
bool isEmpty() const;
psNode<psClass>* front() const;
private:
psNode<psClass>* head;
};
还没有重载的赋值运算符。我打算在我跳过这个障碍后添加它。
【问题讨论】:
-
您应该熟悉The Rule of Three。此外,除非这是家庭作业或学习练习,否则绝对不建议实施您自己的链表。
-
你返回的链表应该被销毁,当然,因为它已经在return语句中复制了,而原始的对于你返回的函数来说是本地的?
-
您可能应该展示如何定义
psList、psNode和psList::pushback。 -
这是有道理的,但函数本地的一个和我返回的一个是内存中的 same list。如果它不是一个动态结构,那么我会声明 someVar,返回 someVar,它会创建一个自身的副本,然后函数中的 someVar 将被删除。但是现在发生的事情是我声明了一些列表,我返回了一些列表,并且由于列表是内存中的地址,我也删除了该列表。也许我正在尝试做一些不可能的事情,但你肯定可以返回一个动态结构而不会以某种方式破坏它。我将提供一些调试器的输出以便更好地解释。
-
我以为您在复制构造函数中进行“深度”复制?如果是这样,它们在内存中不是同一个列表,返回的值是函数本地的一个副本。
标签: c++ constructor destructor