C ++虚拟析构函数 - 内存泄漏
c++ virtual destructor - memory leak
我很难弄清楚如何解决以下问题:
#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;
}
我遇到的问题是内存泄漏,我试图弄清楚如何在 class 超出范围时删除指向它的指针。
至于现在 shout 和 whisperer 不会被删除,这会导致内存泄漏。
看起来唯一的方法是让 SoundProducer class 继承 uppgift1 class 并将析构函数设为虚拟,对吗?我有点累了,如果我也让你感到困惑,我很抱歉:)
Uppgift1.SetSoundProducer
取得传递的 SoundProducer
的所有权,除了不完全这样做:
- 它会
delete
最后一组销毁。
- 但是它不会
delete
以前的设置一个新的。
此外,在创建 Uppgift1
类型的变量时, 成员指针是不确定的 ,您通常会忽略 "rule-of-three",它表示您除了自定义 dtor 之外,还必须定义复制 ctor 和复制赋值。
接下来我们看看成员pointe是如何删除的:
delete t;
由于 t
的类型没有虚拟 dtor,它必须指向指针声明的完全派生类型的对象。
不幸的是,你最后设置了一个 Shouter
,它是派生的 class,因此有 UB.
你应该看看智能指针,尤其是 std::unique_ptr
,在某些情况下 std::shared_ptr
。
您设置了两次 soundproducer,但 UppGift 只能保存一个....因此,Shouter 的析构函数被调用,因为它是最后添加的元素,whisper 的析构函数永远不会被调用,因为您已经将它再次设置为 shouter .
之前:
Uppgift1 uppg1;
uppg1.SetSoundProducer(new Whisperer);
uppg1.SaySomething();
uppg1.SetSoundProducer(new Shouter);
你在片场打了两次电话,但只能保留一次。
SoundProducer* t;
之后:
如果您要添加多个 SoundProducer,请保留 list/vector 个。
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();
在继承树中,如果您尝试通过派生 class 的基 pointer.That 方式删除派生 class 实例,则基 class 析构函数应该是虚拟的当您对指向派生 class 实例的基 class 指针执行删除操作时,会调用析构函数
我已经编辑了代码 now.It works.
#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;
}
我很难弄清楚如何解决以下问题:
#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;
}
我遇到的问题是内存泄漏,我试图弄清楚如何在 class 超出范围时删除指向它的指针。
至于现在 shout 和 whisperer 不会被删除,这会导致内存泄漏。
看起来唯一的方法是让 SoundProducer class 继承 uppgift1 class 并将析构函数设为虚拟,对吗?我有点累了,如果我也让你感到困惑,我很抱歉:)
Uppgift1.SetSoundProducer
取得传递的 SoundProducer
的所有权,除了不完全这样做:
- 它会
delete
最后一组销毁。 - 但是它不会
delete
以前的设置一个新的。
此外,在创建 Uppgift1
类型的变量时, 成员指针是不确定的 ,您通常会忽略 "rule-of-three",它表示您除了自定义 dtor 之外,还必须定义复制 ctor 和复制赋值。
接下来我们看看成员pointe是如何删除的:
delete t;
由于 t
的类型没有虚拟 dtor,它必须指向指针声明的完全派生类型的对象。
不幸的是,你最后设置了一个 Shouter
,它是派生的 class,因此有 UB.
你应该看看智能指针,尤其是 std::unique_ptr
,在某些情况下 std::shared_ptr
。
您设置了两次 soundproducer,但 UppGift 只能保存一个....因此,Shouter 的析构函数被调用,因为它是最后添加的元素,whisper 的析构函数永远不会被调用,因为您已经将它再次设置为 shouter .
之前:
Uppgift1 uppg1;
uppg1.SetSoundProducer(new Whisperer);
uppg1.SaySomething();
uppg1.SetSoundProducer(new Shouter);
你在片场打了两次电话,但只能保留一次。
SoundProducer* t;
之后:
如果您要添加多个 SoundProducer,请保留 list/vector 个。
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();
在继承树中,如果您尝试通过派生 class 的基 pointer.That 方式删除派生 class 实例,则基 class 析构函数应该是虚拟的当您对指向派生 class 实例的基 class 指针执行删除操作时,会调用析构函数 我已经编辑了代码 now.It works.
#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;
}