【问题标题】:Invalid pointer after a call to delete调用删除后指针无效
【发布时间】:2021-06-08 20:10:38
【问题描述】:

我在一个名为 virtual.cpp 的文件中有这个简单的代码:

#include <iostream>


class Parent
{
    public:
    virtual ~Parent(){ std::cout << "Parent Destructor" << std::endl; }

    virtual void VirtualFunction()
    {
        std::cout << "VirtualFunctionInParent" << std::endl;
    }
};

class Child: public Parent
{
    public:
    virtual ~Child() { std::cout << "Child Destructor" << std::endl; }
    virtual void VirtualFunction()
    {
        std::cout << "VirtualFunctionInChild" << std::endl;
    }    
};

int main()
{
    Child child1;
    Parent *parent1 = &child1;
    delete parent1;

}

编译正确

g++ -Wall --pedantic -o virtual virtual.cpp 

但是当我运行它时,我得到这个错误:

./virtual 
Child Destructor
Parent Destructor
free(): invalid pointer
Annullato (core dump creato)

我认为是因为我删除了指针parent1,所以这会擦除指针指向的内存,即&amp;child1。 因此,当 child1 超出范围时,Child 析构函数会尝试释放不再存在的内存。

我的问题:

  1. 我的推理正确吗?
  2. 如果我的推理是正确的,那么处理这种“超出范围”情况的正确方法是什么?

【问题讨论】:

  • 只有deletenew
  • 你会遇到同样的问题加上内存泄漏,因为new Parent; 的地址被覆盖并丢失了。
  • @vaeVictis 既然您已经得到了几个答案,我不建议您使用此空间提出新问题。如果需要,有一个 [ ] 按钮。
  • @vaeVictis -- 关键字delete 并不意味着“擦除”。其目的是通知分配器以前使用new 分配的内存现在可以重用(如果需要)。实际上没有任何东西被“擦除”。 可能发生的是调试运行时将用一个值覆盖该区域,但这就是“擦除”的范围。
  • 你会发现在不知道和使用正确术语的情况下很难与程序员讨论编程。

标签: c++ invalid-pointer


【解决方案1】:

我删除了指针 parent1,所以这会擦除指针指向的内存。我的推理正确吗?

没有。您正在您的删除中获取核心转储。

只有从new 返回的地址可以传递给delete

delete 不会擦除内存,因为内存没有“已擦除”状态的概念。

处理这种“超出范围”情况的正确方法是什么?

删除delete 行。没必要。

在一个范围内创建的任何变量都会在离开该范围时自动管理。

【讨论】:

  • 我没有正确管理术语,谢谢指出。我的意思是删除释放了 parent1 指向的内存。对吗?
  • @vaeVictis delete 将调用所指向对象的析构函数,然后释放或释放内存。是的。
【解决方案2】:

不要在没有使用new 分配的对象上调用delete。此对象将在超出范围时被删除,因此无需特殊操作即可正确销毁它。

如果您希望对象在范围内开始其生命周期并在范围结束时结束其生命周期,请不要使用newdelete。只需正常声明即可。

newdelete 用于您要管理其生命周期的对象。使用new 分配它们,并在完成后调用delete

【讨论】:

    【解决方案3】:

    首先,您不使用new 或任何其他方式来分配动态 内存。所以使用delete是没有意义的。

    要回答您的下一个问题,您必须首先告诉我们为什么要在子地址上创建父指针?

    【讨论】:

    • 我只是在使用虚函数,通常调用parent1-&gt;VirtualFunction() 和动态绑定(希望我使用了正确的术语)。其余代码不存在,因为它不是问题的一部分。
    【解决方案4】:

    更具体地回答您的问题

    1. 我的推理正确吗?

    您永远不会超出范围,因为您在 main() 中将变量声明到当前堆栈帧。为了将变量声明到堆(超出范围),您必须使用动态内存分配。

    Parent * parent1 = new(Child);
    delete(parent1);
    

    这段代码所做的是在堆中创建一个子类,然后创建一个 parent1 指针,该指针位于有效指向子类的范围内。

    【讨论】:

      猜你喜欢
      • 2014-08-22
      • 1970-01-01
      • 2011-08-21
      • 2023-03-17
      • 1970-01-01
      • 2012-07-23
      • 1970-01-01
      • 2016-02-22
      • 2021-07-30
      相关资源
      最近更新 更多