C ++在这里发生了什么

时间:2011-02-07 22:50:44

标签: c++ memory-management new-operator

假设我有一个包含Records的类TwoWayList,而GetRec实际上在堆上创建了一个新列表,这里是方法

void GetRec(TwoWayList<Record> &rec)
{
   TwoWayList<Record>* list= new TwoWayList<Record>();
   Record r;
   list->Insert(&r);
}

现在我有以下两个场景,第一个在我调用delete时死亡,另一个我只是得到一个空的引用记录,所以当我调用MoveToStart()时我得到一个段错误,但是如果我只是删除它有效...

int main () {
    TwoWayList<Record> record;
    GetRec(record);
    record.MoveToStart();
    delete &record;//crash
   return 0;
}

int main () {
    TwoWayList<Record> *record;
    GetRec(*record);
    record->MoveToStart(); //segfault
    delete record;
   return 0;
}

所以这里发生了什么?我在方法的堆中创建一个TwoWayList,因此我不能删除(事实上,如果我不删除它不会是泄漏吗?)是什么方法从这里的方法获取TwoWayList以便我以后可以删除吗?

谢谢

丹尼尔

3 个答案:

答案 0 :(得分:5)

你的第一个main在堆栈上创建记录 - 而不是堆。因此,您尝试delete堆栈变量的地址崩溃。

您的第二个main永远不会分配record。因此,当您尝试使用指针时,会出现段错误。

此外,您的函数分配内存,但随后忘记它并泄漏它。我的意思是你创建一个新的list,但永远不要抓住指针。一旦函数退出,你就不再有指向你创建的列表的指针 - 可能不是你想要做的。

GetRec也会忽略输入参数 - 也可能不是你想要的。

猜猜你在尝试什么......

void GetRec(TwoWayList<Record> &rec)
{
    Record r;
    rec.Insert(r);
}

int main () {
    TwoWayList<Record> record;
    GetRec(record);
    record.MoveToStart();
    return 0;
}

这会创建一个TwoWayList(命名记录),将对记录的引用传递给函数GetRec。 GetRec创建一个Record并将其插入TwoWayList。回到main,它在记录中调用MoveToStart(现在插入了一个Record)。

这可以通过使用堆栈避免任何新/删除问题,当您将其插入TwoWayList时,以成本复制记录。令人怀疑的是,该副本的性能成本对您来说很重要。但如果确实如此,那就说出来。

答案 1 :(得分:1)

void GetRec(TwoWayList<Record> &rec)
{
   TwoWayList<Record> *list= new TwoWayList<Record>();
   Record r;
   list->Insert(&r);
}

好吧,你在堆上分配一些内存,让它的指针超出范围。你确定你不是故意这样做:

rec = new TwoWayList<Record>(); //rec should really be a reference to a pointer

TwoWayList<Record> record;
delete &record;//crash

您无法删除堆栈中的对象。

TwoWayList<Record> *record;
GetRec(*record);
record->MoveToStart(); //segfault
delete record;

这里你的GetRec没有改变记录,我认为你想要的。由于记录指向垃圾,对该对象的调用显然会中断。

答案 2 :(得分:0)

在第一个示例中,您要删除一个不好的局部变量。不需要;当函数超出函数末尾的范围时,变量被“删除”。

您的第二个示例是尝试使用未初始化的指针。您需要使用TwoWayList<Record>分配new的实例。

此外,您的GetRec函数正在堆上分配一个列表,并且从不调用delete,这会导致内存泄漏。