c ++虚拟析构函数 - 内存泄漏

时间:2015-01-25 17:50:40

标签: c++ oop memory-leaks

我很难弄清楚如何解决以下问题:

#include "stdafx.h"
using namespace std;
#define CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

class Talker
{
public:
    virtual void SaySomething() = 0;
};

class SoundProducer
{
protected:
    string soundName;
public:
    SoundProducer(string nameOfSound)
    {
        this->soundName = nameOfSound;      
    }

    virtual void MakeSound() = 0;

    string GetSoundName()
    {
        return this->soundName;
    }
};

class Uppgift1 : public Talker
{
private:
    SoundProducer* t;

public:
    Uppgift1(){};

    void SetSoundProducer(SoundProducer* _soundProducer)
    {
        t = _soundProducer;
    }

    void SaySomething()
    {
        t->MakeSound();
    }

    virtual ~Uppgift1()
    {
        delete t;
    }
};

class Whisperer : public SoundProducer
{
public:
    Whisperer() : SoundProducer("Whisper"){}

    virtual void MakeSound()
    {
        cout << soundName << ": Ssch,hush,hush" << endl;
    }

    virtual ~Whisperer()
    {
        cout << "Whisperer destructor called" << endl;
    }
};

class Shouter : public SoundProducer
{
public:
    Shouter() : SoundProducer("Shout"){}

    virtual void MakeSound()
    {
        cout << soundName << ": WOW YEEEH!!" << endl;
    }

    virtual ~Shouter()
    {
        cout << "Shouter destructor called" << endl;
    }
};

int main()
{
    Uppgift1 uppg1;
    uppg1.SetSoundProducer(new Whisperer);
    uppg1.SaySomething();
    uppg1.SetSoundProducer(new Shouter);
    uppg1.SaySomething();

    _CrtDumpMemoryLeaks();
    return 0;
}

我遇到的问题是内存泄漏,我试图找出如何在超出范围时删除指向类的指针。

至于现在的喊叫和低声说话不会被删除,导致内存泄漏。

看起来这样做的唯一方法是让SoundProducer类继承uppgift1类并使析构函数变为虚拟,我是对的吗?我有点累,很抱歉,如果我也困惑你:)

2 个答案:

答案 0 :(得分:0)

Uppgift1.SetSoundProducer取得了所传递的SoundProducer的所有权,除了不那么做:

  1. 它将delete最后一个设置为销毁。
  2. 但是在设置新的时赢了delete前一个
  3. 此外,在创建Uppgift1类型的变量时,成员指针不确定,并且您通常会忽略&#34;三规则&#34;,其中除了自定义dtor之外,你确实必须定义copy-ctor和copy-assignment。

    接下来,让我们看一下如何删除成员pointe:

    delete t;
    

    由于t的类型没有虚拟dtor,它必须指向指针声明的完全派生类型的对象。
    不幸的是,你设置的是Shouter last,这是一个派生类,因此有UB。

    你应该看一下智能指针,特别是std::unique_ptr,有时还会看std::shared_ptr

答案 1 :(得分:0)

你设置了两次声音生成器,但是UppGift只能容纳一个....因此,Shouter的析构函数被调用,因为它是最后添加的元素,并且声速器的析构函数永远不会被调用,因为你已经将它再次设置为shouter。 / p>

在:

Uppgift1 uppg1;
uppg1.SetSoundProducer(new Whisperer);
uppg1.SaySomething();
uppg1.SetSoundProducer(new Shouter);

您可以在设置上拨打两次电话,但只能保留一个。

SoundProducer* t;

后:

如果要添加多个SoundProducer,请维护它们的列表/向量。

vector<SoundProducer*> _list;

    virtual ~Uppgift1()
    {
    //    delete t;
     std::vector< SoundProducer*>::iterator it = _list.begin();
    //delete *it;
  for ( ; it != _list.end(); it++ ) 
  {
            delete *it;

  }
_list.clear(); 

在继承树中,如果您尝试通过基指针删除派生类实例,则基类析构函数应该是虚拟的。这样,当您对指向派生的基类指针执行删除时,将调用派生类析构函数类实例 我现在编辑了代码。它有效。

#include <iostream>

using namespace std;
#define CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <vector>
//#include <crtdbg.h>

class Talker
{
public:
    virtual void SaySomething() = 0;
    virtual ~Talker(){cout<<"Talker Destructor"<<endl;}
};

class SoundProducer
{
protected:
    string soundName;
public:
    SoundProducer(string nameOfSound)
    {
        this->soundName = nameOfSound;      
    }

    virtual void MakeSound() = 0;

    string GetSoundName()
    {
        return this->soundName;
    }
    virtual ~SoundProducer(){cout<<"SoundProducer Detructor"<<endl;}
};

class Uppgift1 : public Talker
{
private:
    SoundProducer* t;
     vector<SoundProducer*> _list;
public:
    Uppgift1(){};

    void SetSoundProducer(SoundProducer* _soundProducer)
    {
        if(_soundProducer)
      {  cout<<"pushing into list"<<endl;
        _list.push_back(_soundProducer);
      }
     //   t = _soundProducer;
    }

    void SaySomething()
    {
       // t->MakeSound();
    }

    virtual ~Uppgift1()
    {
    //    delete t;
     std::vector< SoundProducer*>::iterator it = _list.begin();
    //delete *it;
  for ( ; it != _list.end(); it++ ) 
  {
            delete *it;

  }
_list.clear(); 


    }


};

class Whisperer : public SoundProducer
{
public:
    Whisperer() : SoundProducer("Whisper"){}

    virtual void MakeSound()
    {
        cout << soundName << ": Ssch,hush,hush" << endl;
    }

    virtual ~Whisperer()
    {
        cout << "Whisperer destructor called" << endl;
    }
};

class Shouter : public SoundProducer
{
public:
    Shouter() : SoundProducer("Shout"){}

    virtual void MakeSound()
    {
        cout << soundName << ": WOW YEEEH!!" << endl;
    }

    virtual ~Shouter()
    {
        cout << "Shouter destructor called" << endl;
    }
};

int main()
{
    Uppgift1 uppg1;
    SoundProducer* ptr=new Whisperer;
    uppg1.SetSoundProducer(dynamic_cast<SoundProducer*>(ptr));
    uppg1.SaySomething();
    uppg1.SetSoundProducer(new Shouter);
    uppg1.SaySomething();

 //   _CrtDumpMemoryLeaks();
    return 0;
}