我应该对构造函数中由 "new" 运算符初始化的对象成员使用 "delete" 吗?
Should I use the "delete" for the object member which initialized by "new" operator in constructor?
我有一个关于 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
吗?但是这两个是对象的成员。
我可以轻松地在 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 也将是免费的。
所以,deconstructor ~MallarDuck() 中的 delete 就足够了。谢谢.
是的,每当您使用 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;
语句
- 此外,在这种情况下,不要在
MallarDuck
. 的析构函数内的数据成员上显式使用 delete
- 然后如果你看到析构函数不是运行数据成员
m_flyBehavior
和m_quackBehavior
这意味着你有内存泄漏,你需要使用delete
在 MallarDuck
. 的析构函数中显式地在适当的数据成员上
回答您的编辑
how about the input parameter mentioned in the first code block?
对于语句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())
那样调用函数,class应该删除指针。但是用户也可以使用现有指针调用它并在以后删除它。指针会被多次删除。
// Incorrect usage
FlyBehavior* way = new FlyNewWay();
duck1->setFlyBehavior(way);
duck2->setFlyBehavior(way);
delete way;
您的 class 无法知道用户是如何创建指针的。您不应该相信 class 被正确使用。相反,将 std::unique_ptr<FlyBehavior>
作为参数并将其保存在 class.
中
创建参数 std::make_unique
:
mallardDuck->setFlyBehavior(std::make_unique<FlyNewWay>());
我有一个关于 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
吗?但是这两个是对象的成员。
我可以轻松地在 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 也将是免费的。 所以,deconstructor ~MallarDuck() 中的 delete 就足够了。谢谢.
是的,每当您使用 new
关键字分配一些内存时,您必须始终使用 delete
在以后不再需要时释放该内存。否则你会像在你的程序中那样发生内存泄漏。在您的情况下,您应该在 MallarDuck.cpp .
delete
其他解决方案是使用像 unique_ptr
这样的智能指针,这样您就不必显式释放内存。
unique_ptr` 的语法类似于:
unique_ptr<FlyWithWings> m_flyBehavior(new FlyWithWings());
如果您对是否存在内存泄漏感到困惑,可以在FlyWithWings
和SimpleQuack
的析构函数中添加cout
语句来确认是否存在内存泄漏是否在这些对象上调用析构函数。然后相应地你可以根据需要使用智能指针。
确认是否有内存泄漏的步骤
- 在
FlyWithWings
和SimpleQuack
. 的析构函数中添加一些 - 此外,在这种情况下,不要在
MallarDuck
. 的析构函数内的数据成员上显式使用 - 然后如果你看到析构函数不是运行数据成员
m_flyBehavior
和m_quackBehavior
这意味着你有内存泄漏,你需要使用delete
在MallarDuck
. 的析构函数中显式地在适当的数据成员上
std::cout<<"destructor ran;
语句
delete
回答您的编辑
how about the input parameter mentioned in the first code block?
对于语句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())
那样调用函数,class应该删除指针。但是用户也可以使用现有指针调用它并在以后删除它。指针会被多次删除。
// Incorrect usage
FlyBehavior* way = new FlyNewWay();
duck1->setFlyBehavior(way);
duck2->setFlyBehavior(way);
delete way;
您的 class 无法知道用户是如何创建指针的。您不应该相信 class 被正确使用。相反,将 std::unique_ptr<FlyBehavior>
作为参数并将其保存在 class.
创建参数 std::make_unique
:
mallardDuck->setFlyBehavior(std::make_unique<FlyNewWay>());