C++ 析构函数在返回动态结构的函数中删除副本

C++ 析构函数在返回动态结构的函数中删除副本,c++,constructor,destructor,C++,Constructor,Destructor,好了,各位,没问题 所以我有一个模板类实现了一个单链表。我的程序中的类中的函数返回这些列表之一 psList<int> psObj::getList() const { return List; } 下面是getList函数中的“返回列表”列表 head 0x616080 data 2 next 0x616060 data 12 next 0x0 同样的事情 下面是复制构造函数末尾的“原始”和“此”列表 “这个” “原件” 一切看起来都很好,不是吗 现在我们回到getList函

好了,各位,没问题

所以我有一个模板类实现了一个单链表。我的程序中的类中的函数返回这些列表之一

psList<int> psObj::getList() const {
 return List;
}
下面是getList函数中的“返回列表”列表

head 0x616080
data 2
next 0x616060
data 12
next 0x0
同样的事情

下面是复制构造函数末尾的“原始”和“此”列表

“这个”

“原件”

一切看起来都很好,不是吗

现在我们回到getList函数,即将进入最后一个括号

psList<int> psObj::getList() const {
 return List;
} // This bracket
现在我们进入最后一个括号,析构函数被称为

/* 
 * 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;
    }
};
//具有默认构造函数的简单单链接节点将链接初始化为NULL。
模板
结构psNode{
psClass数据;
psNode*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;
    }
}
模板
void psList::pushback(psClass对象){
psNode*ptr=新的psNode;
ptr->data=对象;
if(head==NULL)
水头=ptr;
否则{
//我现在必须找到尾巴
psNode*尾;
psNode*迭代器=头;
while(迭代器!=NULL){
尾部=迭代器;
迭代器=迭代器->下一步;
}
tail->next=ptr;
}
}
是的,我知道跟踪尾巴会更容易

以下是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;
};
模板
类列表{
公众:
psList();
~psList();
psList(常数psList和原件);
psList(psNode*_头);
无效擦除();
void pushfront(psClass对象);
void pushback(psClass对象);
bool isEmpty()常量;
psNode*front()常量;
私人:
psNode*头;
};

还没有重载的赋值运算符。我计划在跳过这一障碍后添加它。

似乎
psList
的复制构造函数生成的是浅复制,而不是深复制。通常,如果管理类中的资源,则需要非平凡的复制构造函数、赋值运算符和析构函数(“三大”)。请向我们显示
psList

的代码,您当前正在执行的操作如下:

psList<int> psObj::getList() const { return psList<int>(List); }
psList<int> newList; // psList default constructor called
newList = obj.getList(); // 1) obj.List copied via copy constructor within getList
                         // 2) copy of obj.List copy-assigned to newList (simple copy of head pointer)
                         // 3) copy of obj.List destructed
// newList now has head pointing to destroyed data
使用复制构造函数。通常情况下,两个副本会被压缩为一个副本

或者,如果要复制到现有对象,如中所示

psList<int> newList;
newList = obj.getList();
因此,在调用代码中发生的情况如下:

psList<int> psObj::getList() const { return psList<int>(List); }
psList<int> newList; // psList default constructor called
newList = obj.getList(); // 1) obj.List copied via copy constructor within getList
                         // 2) copy of obj.List copy-assigned to newList (simple copy of head pointer)
                         // 3) copy of obj.List destructed
// newList now has head pointing to destroyed data
psList newList;//psList默认构造函数调用
newList=obj.getList();//1) 通过getList中的复制构造函数复制的对象列表
//2)分配给新列表的对象列表副本(头指针的简单副本)
//3)已销毁对象列表的副本
//新列表现在的标题指向已销毁的数据
在您的情况下,这不是您想要的,您应该做的是确保拷贝分配真正形成了预期的深度拷贝(请参阅,以获取通过您已经实现的拷贝构造函数实现此操作的方法)

因此:如果您需要定义自己的析构函数、复制构造函数和复制赋值中任意一个的实现,那么您需要全部定义它们(或者至少将复制赋值和复制构造函数声明为private以使您的类不可复制)

另外,为什么不返回一个引用:

const psList<int> & psObj::getList() const { return List; }
constpslist&psObj::getList()const{return List;}
并让调用函数决定是否复制

psList<int> localList(localPsObj.getList());
psList localList(localPsObj.getList());

你应该熟悉一下。此外,除非这是家庭作业或学习练习,否则绝对不建议实现您自己的链表。您返回的链表肯定会被销毁,因为它已复制到return语句中,并且原始链表是您从中返回的函数的本地链表。您可能应该展示如何
psList
,定义了
psNode
psList::pushback
。这是有道理的,但函数的本地部分和我返回的部分在内存中是相同的列表。如果它不是一个动态结构,那么我将声明someVar,返回someVar,它将创建自身的副本,然后函数中的someVar将被删除。但是现在我声明了一些列表,返回了一些列表,因为列表是内存中的地址,所以我也删除了列表。也许我在尝试做一些不可能的事情,但你肯定可以返回一个动态结构,而不会以某种方式破坏它。我将提供调试器的一些输出以更好地解释。我以为您在复制构造函数中进行“深度”复制?如果是这样的话,它们在内存中不是同一个列表,返回的值是函数的本地值的副本。不,深度复制和深度析构函数两者。您是如何得出这个结论的?构造函数的未知部分(
pushback
)只接收
psNode
数据
部分,因此它很难重建指向原始
psNode
的指针。不,复制构造函数肯定会进行深度复制。pushback创建指向空白新节点的指针,将数据复制到此节点中,然后将已生成列表中的最后一个节点链接到该节点(链接到null之前)。新节点中的链接已经指向null,因此没有任何操作。@Charles:好的,遗漏了只有数据传递到
pushback
。请原谅我的无知,但是为什么我需要做psList psObj::getList()const{return psList(List);}据我所知,当函数需要返回值时,它会调用copy cons
psList<int> psObj::getList() const { return psList<int>(List); }
psList<int> newList = obj.getList(); // same as psList<int> newList(obj.getList());
psList<int> newList;
newList = obj.getList();
psList & psList::operator=(const psList& src) {
  head = src.head;
}
psList<int> newList; // psList default constructor called
newList = obj.getList(); // 1) obj.List copied via copy constructor within getList
                         // 2) copy of obj.List copy-assigned to newList (simple copy of head pointer)
                         // 3) copy of obj.List destructed
// newList now has head pointing to destroyed data
const psList<int> & psObj::getList() const { return List; }
psList<int> localList(localPsObj.getList());