Reputation: 13
So i will get straight to the point: I have a function that is adding some stuff (which happens to be a class) to another class:
tower->set_weapon(new NoWeapon());
The set_weapon() is a simple method in the tower class, which associated a inner variable with this new NoWeapon class it receives.
virtual void set_weapon(Weapon* weapon){ weapon_ = weapon; };
weapon_ is a pointer to the Weapon class, and NoWeapon is hierarchically the son of weapon. When everything is said and done, the tower itself cleans everything up:
weapon_->Clean();
delete weapon_;
However, im still getting a memory leak. Im using vld on VisualStudio 2013, and it detects a memory leak on the first line i mentioned
tower->set_weapon(new NoWeapon());
Any idea why this is happening and how could i work around it?
Thank you in advance!
EDIT: Thanks to YSC for the solution. I was in fact getting a leak over not initializing the original weapon pointer, but your ideas got me back on track.
As for the unique_ptr ideas, i played with it before, but it wasn't the solution i was looking for. Thanks for your help anyway.
Upvotes: 1
Views: 469
Reputation: 40060
We lack context information, but basically if Tower::set_weapon()
is called twice, Tower::weapon_
get overwritten and memory leaks. Suggestion:
Tower::Tower()
: weapon_(nullptr)
{}
void Tower::set_weapon(Weapon* weapon)
{
if (weapon_ != nullptr)
{
weapon_->Clean(); // should be called by Weapon::~Weapon()
}
delete weapon_;
weapon_ = weapon;
};
You could also use an std::unique_ptr
:
class Tower
{
std::unique_ptr<Weapon> weapon_;
public:
Tower::Tower() {}
void set_weapon(std::unique_ptr<Weapon> weapon)
{
// assume Weapon::~Weapon() is fixed
weapon_ = std::move(weapon);
};
};
Upvotes: 3
Reputation: 69854
note: YSC's answer is correct. A weapon should not need a Clean
method as it can handle resource deallocation in a destructor.
However, if there really is some reason for the call to Clean
, you can encapsulate all this in std::unique_ptr
with a custom deleter.
like so:
struct weapon_cleaner
{
void operator()(Weapon* pw) const nothrow {
if (pw) {
try {
pw->Clean();
}
catch(...) {
}
}
delete pw;
}
};
using weapon_pointer = std::unique_ptr<Weapon, weapon_cleaner>;
class Tower
{
weapon_pointer weapon_;
public:
Tower::Tower() {}
void set_weapon(weapon_pointer weapon)
{
weapon_ = std::move(weapon);
};
};
called like so:
weapon_pointer make_machine_gun() {
return weapon_pointer(new MachineGun(),
weapon_cleaner());
}
mytower.set_weapon(make_machine_gun());
Upvotes: 1