我在我的代码中使用动态内存分配,并在尝试删除指向子类的指针时遇到问题。我发现当我使用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;
}
我想它与基类中的析构函数的语法有关。即使我为子类创建自定义析构函数,也会出现同样的问题。
有什么想法吗?
答案 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)
该指针的内存分配两次。所以你永远不会释放你新的所有记忆。只需将指针设为私有成员,并仅在基类中分配它。