涉及继承、指针对象的释放以及何时这样做的问题

Posted

技术标签:

【中文标题】涉及继承、指针对象的释放以及何时这样做的问题【英文标题】:Questions involving inheritance, Deallocation of pointer objects and when to do so 【发布时间】:2017-04-27 17:53:51 【问题描述】:

我目前在上编程课,发现老师不太擅长如何使用我们所教的概念。我已经搜索了有关我的主题的多个问题,但实际上并没有从中获得太多帮助。抱歉,如果其中一些看起来相似。

1) 在处理父/子对象时,假设您有一个类 VehicLot,它添加了一个车辆对象子对象(摩托车对象、汽车对象、卡车对象)以及这些对象的数量到 vector <Vehicle*> lot。在这样的情况下,我似乎无法理解发生了什么。我不确定我是否也正确解除分配。 (我突然想到了这个,如果这看起来像一个愚蠢的例子,我很抱歉。这与我几周前遇到的问题很接近。)

void VehicLot::addVehic(int typeNum, int numVehic) 
    if(typeNum == 1)
        Car* newCar = new Vehicle();
        for(int i = 0; i < numVehic; i++)
            lot.push_back(newCar);
    delete newCar;
    newCar = NULL;
    

那么,在这段代码中,这是否正确地添加了一个 Car(在此中将是类型 #1)对象作为车辆的向量?如果是这样,我是否也正确地释放了内存?抱歉,如果此代码中的任何一个在其他方面不正确,我有点想出这个来模拟让我感到困惑的区域。是否创建新对象以临时“使用”类函数将数据存储在其他事物中?为了进一步解释这一点,我制作这些临时车辆对象仅仅是为了将这些对象添加到一个可以实际保存数据以供以后使用的向量中的原因吗?这些问题引出了问题2。

2) 到目前为止,我在计算机科学领域遇到的最大问题之一是段错误。经过一些研究,我发现这通常是由于访问了“不存在”的内存。这是一个合理的描述方式吗?您能否就我应该搜索与段错误有关的内容提供任何提示?由于我删除指针的概念似乎有点模糊,我假设我的问题在于没有正确删除指针/对象。

由于我正在学习这方面的课程,我应该补充一点,我不知道我在这里看到的许多“捷径”。我需要了解我的问题,但也需要能够以我期望的方式做事。我真的很感激这方面的任何帮助,因为我已经进行了大量研究,但无法理解我必须改进的地方。

【问题讨论】:

如果初学者课程教手动内存管理,那么它可能不是很好。 我会说,我不一定是“初学者”。我想我会认为它适合那些了解基础知识并且现在正在扩展更多内容的人。我过去做过各种各样的事情,比如函数、递归,以及所有你可以认为是制作程序的“支柱”的东西。它越来越详细,我很喜欢,但由于老师的原因(或者至少与我的学习方式相比,他的教学方式),这门课似乎更难了。 到目前为止,我在计算机科学领域遇到的最大问题之一是 seg faults -- 问题不是计算机科学 -- 你使用的是一种语言,C++,这依赖于程序员从上到下知道如何正确处理动态分配的内存。 Java 没有这样的“分段错误”需要处理。如果这门课程是 C++,并且如果他们想让你走这条路,一个更好的任务是尝试构建你自己的工作 vectorstring 类,而不是这些使用 @987654326 的“一次性”尝试@ 和 delete. 我同意他们有办法改善给出的问题,但我被他们给我的问题所困扰,所以我需要知道如何以“他们”希望我的方式解决它们做。我个人认为这只是让我更难,但是哦,好吧。我的做法至少是正确的吗? 您所做的只是在向量中存储相同的指针值是不正确的。这样做有什么好处?另外,你已经deleted 那个指针值,所以现在你的向量lot 包含的指针值都是无效的,所以向量本身现在对你没有用了。 【参考方案1】:

经过一些研究,我发现这通常是由于访问了“不存在”的内存。

这意味着您正在访问编译器为您的程序分配的内存之外的内存。

当您声明一个数组时,比如说int arr[3],您的编译器会在内存中保留 3 个空间,每个空间长 8 个字节。现在,这个内存空间可以在任何地方;紧随其后的内存块可能会分配给某些内部计算机进程。当您不小心尝试访问它时(比如说arr[5]),您正在查看应该超出您范围的内存。如果该内存块为空,程序将继续正常运行。但是,如果它是为另一个进程保留的,则会遇到段错误。

这就是为什么它被称为未定义的行为;如果您的代码触及不可访问的内存,您可能会遇到段错误,或者如果您的程序踩到空内存,您的程序可能会继续运行。但是,两者都是错误的,您的数组不应超出范围。

希望对你有帮助

【讨论】:

因此,如果我遇到 seg 错误,这可能是由于我访问的数组或向量超出了它的范围?谢谢,我必须确保将来检查类似的东西。这是段错误的最常见原因吗? @bake、越界访问和释放后使用是导致分段错误的最常见原因 “免费后使用”? @bake char *ptr = new char[10]; delete [] ptr; delete [] ptr; -- 刚刚删除的指针值出现双重删除错误。 根据我的经验,这主要是我遇到的段错误【参考方案2】:

在您的示例代码中,您创建了一个 Vehicle 对象,然后将指向它的 numVehic 指针复制到向量中,然后删除向量中所有这些点指向的对象。所以向量中的所有指针都指向不再有效的内存。

假设你想要独立在向量中,你应该做的是

void VehicLot::addVehic(int typeNum, int numVehic) 
    if(typeNum == 1)
        for(int i = 0; i < numVehic; i++) 
            lot.push_back(new Car);
        
    

如果不更改包含lot 成员变量的类的析构函数,这将导致内存泄漏。因此,您需要调整该类的析构函数以遍历向量中的所有元素并在它们上调用delete,这看起来类似于此

~ClassThatContainsLotVariable::ClassThatContainsLotVariable() 
    for (auto vehicle : lot) 
        delete vehicle;
    

然而,最好的解决方案是将lot 的定义更改为std::vector&lt;std::unique_ptr&lt;Vehicle&gt;&gt;,这样您就根本不需要关心内存管理 - 编译器生成的包含@ 的类的默认解构器987654329@ 成员变量会自动为你做清理工作。此外,这将有助于识别您意外共享同一对象的位置(如前所述,这就是您的示例中发生的情况),因为您无法复制 unique_ptr。

【讨论】:

但是如果我想在向量中添加一个特定的对象类型,是不是也像lot.push_back(new Car());一样,非常感谢你的帮助。 @bake 这就是为什么我问Car 是从Vehicle 派生的还是反过来的:) 从你的示例代码看来Car 是基类。现在已经修复了。 再次感谢。这开始变得有意义了。

以上是关于涉及继承、指针对象的释放以及何时这样做的问题的主要内容,如果未能解决你的问题,请参考以下文章

何时释放带有“自动释放”的对象?

分配和释放 VS。自动释放。为啥和何时?

C ++何时返回指针[关闭]

boost库之智能指针

何时使用自动释放变量? [复制]

对象释放期间的问题