C++ 如何在设计实现级别避免内存泄漏

C++ 如何在设计实现级别避免内存泄漏,c++,object,inheritance,memory-management,memory-leaks,C++,Object,Inheritance,Memory Management,Memory Leaks,几天前我在C++中看到了一个关于内存泄漏的面试问题。 代码如下(如果我没记错的话): #包括 使用名称空间std; 超级班{ int值; int arr[1000]; 公众: super():值(0){} super(int-value):value(value){} 虚拟int getValue()常量{ 返回此->值; } }; 组别分组:公共超级{ int-val; 超级超级超级; 向量v1; 公众: sub():val(0),sup(0){} sub(int值):val(值),sup(值

几天前我在C++中看到了一个关于内存泄漏的面试问题。 代码如下(如果我没记错的话):

#包括
使用名称空间std;
超级班{
int值;
int arr[1000];
公众:
super():值(0){}
super(int-value):value(value){}
虚拟int getValue()常量{
返回此->值;
}
};
组别分组:公共超级{
int-val;
超级超级超级;
向量v1;
公众:
sub():val(0),sup(0){}
sub(int值):val(值),sup(值),v1(10,0){
int getValue()常量{
返回此->val;
}
};
int main(){
sub*pt1=新(sub);
super*pt2=pt1;
pt1=新的(sub);
删除pt2;//内存泄漏??
//更多代码在这里。。。
删除pt1;
返回0;
}
问题是如何在实现设计级别避免这种类型的内存泄漏。我想问题不仅仅是回答“不要使用那样的指针”

它是否与将析构函数实现为虚拟或使用动态强制转换有关?我们如何实现析构函数,以便
delete pt2
不会产生任何内存泄漏?有人能进一步分析这个例子吗


提前感谢。

首先,
删除pt2并不是特别的内存泄漏。我最初说它是未定义的行为,因此标准允许任何行为,包括内存泄漏。但是在仔细检查这些类之后,实际上,对于使用
int
数组的代码的第一个版本,
sub
是可破坏的,因此,尽管看起来很奇怪,但这段代码是正确的。然后您更改了代码,使
sub
不再具有可破坏性(由于
vector
数据成员),因此它现在是未定义的行为

提出问题的人可能一直在寻找一个具体的答案,如果是的话,我不知道那是什么,但这个错误可以通过多种方式“设计出来”:

  • super
    的析构函数设为虚拟,以便通过父指针删除
    sub
    。一个常见的经验法则是,具有虚拟函数的类应该始终具有虚拟析构函数,因为此类类被设计为通过指向基类的指针/引用来使用
  • 在用户代码中,使用RAII技术确保正确销毁。在本例中,使用智能指针
    shared_ptr
    允许您编写
    shared_ptr pt2(new sub())即使有一个非虚析构函数,对象也会被正确删除,尽管有些人认为这个特性是模糊的。
  • 这很难称之为“实现设计”决策,因为“不要犯严重的编码错误”不是设计规则,而是语言规则。但是调用代码可以“设计”为不通过指向对象基类的指针删除对象,除非这样做是有效的(对于这个类来说不是)。类可以通过一致的文档帮助实现这一点
  • 在类
    super
    sub
    中,使用
    vector
    而不是普通的
    int
    数组。这使得对象本身更小,将大部分数据存储在外部,因此对于像本例这样的使用,用户不觉得他们必须动态分配对象,而是可以将它们放在堆栈上(并不是说1000个整数一定不能放在堆栈上,只是这个大小可能会让用户感到紧张)。因此,如果您对
    super
    进行了与对
    sub
    相同的更改,那么调用代码可以通过尽可能使用自动变量而不是动态分配作为设计原则来降低此类错误的风险

  • 这不是典型的内存泄漏。一个典型的内存泄漏将有一个内存分配,而没有释放。您的新/删除对实际上是匹配的

    这是未定义的行为。您会看到一个相当长的解释,为什么使用
    公共
    而非
    虚拟
    析构函数会产生问题


    对于他们特定的编译器,这可能会泄漏内存,因为编译器在面对未定义的行为时尽可能表现正常。另一个编译器或其编译器的另一个版本可能会爆炸或创建粉色舞动的独角兽。这不是一个内存泄漏的好例子,因为内存泄漏是编译器在更糟糕的情况下能够产生的最好结果。

    如果您在设计级别要求解决方案,讨论可能会非常广泛。
    我相信你们并没有真正讨论如何实现析构函数

    <>强>设计级别< /强>讨论如何避免“内存泄漏”已经由<>强> > >强> > C++领域中的专家:p> 我建议观看他们的演示视频并阅读他们的文章

    • StroutStrup视频:
    • 萨特视频:
    • 文章

    它会泄漏内存,因为
    super
    没有虚拟析构函数(
    virtual~super()=default;

    现在,当您在指向
    sub
    super*
    上调用delete时,不会调用
    sub
    的析构函数,从而泄漏其资源


    如果从基类派生的任何类有任何资源要释放,则始终将基类析构函数声明为虚拟。

    我看不出这是如何泄漏内存的。您正在通过指向其基类的指针删除第一个
    sub
    对象,这应该可以,因为
    sub
    不包含任何资源。如果是的话,你必须在
    super
    中声明一个虚拟析构函数。我猜这里缺少虚拟析构函数。请看@RolandW是的,我不记得示例的确切代码。请随意编辑问题中的代码,以便子类可以容纳资源。只需将
    ar
    更改为向量即可。将sub强制转换为super并将其删除时,super dtor不会调用sub d