我有一个关于new
和delete
的问题:我是否应该使用delete
作为输入参数或成员对象,例如:
https://github.com/jwbecalm/Head-First-Design-Patterns-in-CPP/blob/main/ch01_Strategy/main.cpp
应该在new FlyNewWay()
分配的对象上使用delete
吗?
// change behavior in runtime
mallardDuck->setFlyBehavior(new FlyNewWay());
// create custom MallarDuck on stack.
MallarDuck rocketDuck = MallarDuck(new FlyWthRocket(), new NewQuack());
和在MallardDuck构造函数中:
https://github.com/jwbecalm/Head-First-Design-Patterns-in-CPP/blob/main/ch01_Strategy/MallarDuck.cpp
MallarDuck:: MallarDuck(){
cout << "in MallarDuck:: MallarDuck()" << endl;
// 为MallarDuck 赋值其特有的行为
m_flyBehavior = new FlyWithWings();
m_quackBehavior = new SimpleQuack();
}
我应该使用delete
来释放m_flyBehavior
和m_quackBehavior
吗?但这两个都是object的成员。
我可以很容易地在MallarDuck
的析构函数中添加delete
。
MallarDuck::~MallarDuck(){
cout << "in ~MallarDuck()" << endl;
delete m_flyBehavior;
delete m_quackBehavior;
}
但是第一个代码块中提到的输入参数呢?还是不推荐这种设计和传递价值的方式?你有什么建议吗?
setFlyBehavior()如下,如果我添加删除fb,它将删除m_flyBehavior也为我的理解,因为fb和m_flyBehavior都指向相同的内存地址。
void Duck::setFlyBehavior(FlyBehavior* fb){
m_flyBehavior = fb;
cout << "in Duck::setFlyBehavior()" <<endl;
}
setFlyBehavior()之后的, fb和m_flyBehavior都指向相同的内存地址。所以在解构器:~MallarDuck()中,如果我删除m_flyBehavior,它指向的输入参数fb也将是自由的。因此,在解构器~MallarDuck()中删除就足够了。thx .
是当你使用new
关键字分配一些内存时,你必须总是使用delete
在以后不再需要的时候释放内存。否则,您将出现内存泄漏,就像您的程序一样。在你的例子中,你应该在MallarDuck.cpp的析构函数中使用delete
。
另一个解决方案是使用像unique_ptr
这样的智能指针,这样你就不必显式地释放内存。
unique_ptr的语法类似于:
unique_ptr<FlyWithWings> m_flyBehavior(new FlyWithWings());
如果您对是否存在内存泄漏感到困惑,您可以在FlyWithWings
和SimpleQuack
的析构函数中添加cout
语句,以确认是否在这些对象上调用析构函数。因此,如果需要的话,可以使用智能指针。
确认是否存在内存泄漏的步骤
- 在
FlyWithWings
和SimpleQuack
的析构函数中增加一些std::cout<<"destructor ran;
语句 同样,在这种情况下,不要在 - 然后,如果你看到析构函数没有在数据成员
m_flyBehavior
和m_quackBehavior
上运行,这将意味着你有内存泄漏,你需要在MallarDuck
的析构函数中显式地在适当的数据成员上使用delete
。
MallarDuck
的析构函数中的数据成员上显式地使用delete
。回答你的编辑
对于语句第一个代码块中提到的输入参数如何?
mallardDuck->setFlyBehavior(new FlyNewWay());
,可以使用以下代码:
void Duck::setFlyBehavior(FlyBehavior* fb){
//delete the old memory but note again we should check whether the pointer is valid or not
//check for a valid pointer
if (m_flybehavior)
{
delete m_flybehavior;//free the old memory
}
m_flyBehavior = fb;//so m_flybehavior points to some new memory
//no need to use delete now on m_flybehavior because in the destructor ~MallarDuck() you have delete m_flybehavior
cout << "in Duck::setFlyBehavior()" <<endl;
}
对于语句
MallarDuck rocketDuck = MallarDuck(new FlyWthRocket(), new NewQuack());
因为MallarDuck
的析构函数有delete
作为数据成员,它将释放该内存。此外,这假定输入参数已分配给数据成员。
所有使用new
创建的指针必须在某个时候删除。在c++中,你通常不会给像setFlyBehavior()
这样的函数一个指针,因为谁应该删除指针并不明显。然而,似乎你正在使用多态性,所以你需要使用某种指针。
如果函数像setFlyBehavior(new FlyNewWay())
那样被调用,类应该删除指针。但是用户也可以用一个现有的指针调用它,然后删除它。该指针将被多次删除。
// Incorrect usage
FlyBehavior* way = new FlyNewWay();
duck1->setFlyBehavior(way);
duck2->setFlyBehavior(way);
delete way;
你的类无法知道用户是如何创建指针的。您不应该相信类正在被正确地使用。相反,将std::unique_ptr<FlyBehavior>
作为参数并保存在您的类中。
用std::make_unique
:
mallardDuck->setFlyBehavior(std::make_unique<FlyNewWay>());