如何通过带有指向基类的指针的删除运算符释放内存

How is memory deallocated by delete operator with pointer to base class

本文关键字:指针 删除 释放 内存 运算符 基类 何通过      更新时间:2023-10-16

请考虑以下代码:

class base{
T* obj=new T[40];
//...
public:
base(){/*...*/}
virtual ~base(){
delete[] obj;
//...
}
...
};
class derived : public base{
T* obj2=new T[20];
//...
public:
derived(){/*...*/}
~derived(){
delete[] obj2;
//...
}
...
};
void func(){
base&& exmp=giveder();    //giveder() returns derived
base* dis=new derived[50];
//...
delete[] dis;
}

在上面的代码中,exmp将被正确销毁,因为析构函数被声明为虚拟。但我的问题是,dis指出的免费商店是否会按预期被释放,如果是,那么如何?

很明显,sizeof(base)sizeof(derived)是不同的。但这不会惹exmp尽管它会惹dis吗?我认为它不起作用,因为无法从指针到基数找出sizeof(derived),因此它无法确定需要释放多少字节。虽然我真的很想知道语言规范以及它是否合法。如果这是合法的,那么释放收购中的内容的解决方法是什么?

一个附带的问题,数组不知道它自己的大小(对吧?(,那么析构函数中的delete[] objdelete[] obj2将如何释放内存?

我是指针和内存管理的新手,所以我更喜欢描述性答案。谢谢

您的代码具有未定义的行为。

可以使用

base* ptr = new derived();
delete ptr;

但是不能使用

base* ptr = new derived[10];
delete [] ptr;

以下是 C++11 标准中的相关文本(强调我的(:

在第一种替代方法(删除对象(中,如果要删除的对象的静态类型与其动态类型不同,则静态类型应是要删除的对象的动态类型的基类,并且静态类型应具有虚拟析构函数或行为未定义。在第二种备选方案(删除数组(中,如果要删除的对象的动态类型与其静态类型不同,则行为未定义。

正如其他人已经注意到的那样,这是:

base* dis=new derived[50];
delete[] dis;

未定义的行为。例如,阅读这个问题以了解原因:为什么通过基指针delete[]派生对象数组是未定义的行为?

作为解决方案,我建议使用唯一指针的向量

struct Base { virtual ~Base() = default; };
struct Derived : Base {
Derived() { std::cout << "Derived constructed...n"; }
~Derived() { std::cout << "Derived destroyed...n"; }
};
int main() {
std::vector<std::unique_ptr<Base>> v;
std::generate_n(std::back_inserter(v), 50,
[]{ return std::make_unique<Derived>(); });
}

现场演示:https://wandbox.org/permlink/jcG71bDb1U7wsp2T。

当然,在这种情况下,Derived对象不会放置在连续的内存块中。