删除指向子类的指针时,C ++内存未释放

时间:2013-03-22 01:15:44

标签: c++ inheritance dynamic-memory-allocation

我在我的代码中使用动态内存分配,并在尝试删除指向子类的指针时遇到问题。我发现当我使用delete关键字时,最初分配的内存不会被释放。该功能适用​​于原始基类。

这是一个问题,因为我在arduino上运行代码,RAM很快被吃掉然后崩溃。

以下是一些示例代码:

class Base
{
public:
    Base(){
        objPtr = new SomeObject;
    }
    ~Base(){
        delete objPtr;
    }
    SomeObject* objPtr;
};

class Sub : public Base
{
public:
    Sub(){
        objPtr = new SomeObject;
    }
};



// this works fine
int main()
{
    for (int n=0;n<100;n++) // or any arbitrary number
    {
        Base* basePtr = new Base;
        delete basePtr;
    }
    return 0;
}

// this crashes the arduino (runs out of RAM)
int main()
{
    for (int n=0;n<100;n++) // or any arbitrary number
    {
        Sub* subPtr = new Sub;
        delete subPtr;
    }
    return 0;
}

我想它与基类中的析构函数的语法有关。即使我为子类创建自定义析构函数,也会出现同样的问题。

有什么想法吗?

5 个答案:

答案 0 :(得分:5)

在C ++中,constructors are called upwards in the hierarchy,也就是说,当您创建Derived时,Base()会在Derived()之前执行。这意味着您正在运行objPtr = new SomeObject;两次,并且只删除一次。

您还应该使基类析构函数为虚拟,特别是如果您要从Derived ptr中删除Base个实例。

答案 1 :(得分:3)

您应该使基类'析构函数为虚拟。

virtual ~Base(){
    delete objPtr;
}

答案 2 :(得分:1)

Sub :: Sub()构造函数分配第二个额外的SomeObject 在第一个由Base :: Base()超级构造函数分配之后 并且第二个分配的指针被分配给objPtr引发泄漏。

注意:Sub :: Base()是由Sub :: Sub()

隐式调用的

解决方案:只需在Sub :: Sub()

中删除不必要的分配

另一个建议:使用继承

建议使您的Base析构函数为虚拟
virtual ~Base(){
    delete objPtr;
}

答案 3 :(得分:0)

当你创建派生类时,它首先调用Base类构造函数,然后调用Sub构造函数,你可以在这里看到:

class Base
{
public:
    Base(){
       std::cout << "Base() ctor" <<std::endl ;
        objPtr = new int;
    }
    ~Base(){
        delete objPtr;
    }
    int* objPtr;
};

class Sub : public Base
{
public:
    Sub(){
       std::cout << "Sub() ctor" <<std::endl ;
    objPtr = new int;
    }
};

所以你最终在new中两次调用Base,然后在Sub中第二次调用Base。然后,virtual中分配的内存将丢失,并且您有泄漏。您还需要使析构函数{{1}}使其与派生类一起正常工作。

答案 4 :(得分:0)

该指针的内存分配两次。所以你永远不会释放你新的所有记忆。只需将指针设为私有成员,并仅在基类中分配它。