动态记忆的删除是如何真正起作用的
How does deletion of dynamic memory really work?
我主要有两种类型的对象:Person和Pet。一个人可以养很多宠物。我正在动态地创建这两种类型的对象。
#include <iostream>
#include <string>
#include <vector>
struct Pet
{
Pet() { }
Pet(std::string name, std::string type)
{
Name = name;
Type = type;
std::cout << Name << " is created" << std::endl;
}
~Pet()
{
std::cout << Name << " is destroyed" << std::endl;
}
std::string GetName() { return Name; }
std::string GetType() { return Type; }
std::string Name;
std::string Type;
};
struct Person
{
Person(std::string name)
{
Name = name;
std::cout << Name << " is created" << std::endl;
}
~Person()
{
std::cout << Name << " is destroyed" << std::endl;
}
void AddPet(Pet& pet)
{
Pets.push_back(pet);
}
std::string GetPersonsPets()
{
if (Pets.size() == 0)
{
return Name + " has no pets";
}
if (Pets.size() == 1)
{
return Name + " has " + Pets[0].GetName() + ",a " + Pets[0].GetType();
}
}
std::string Name;
std::vector<Pet> Pets;
};
int main()
{
Person* peter = new Person("Peter");
Person* alice = new Person("Alice");
Pet* fluffy = new Pet("Flyffy", "dog");
peter->AddPet(*fluffy);
std::vector<Person*> People;
People.push_back(peter);
People.push_back(alice);
int i = 0;
for (std::vector<Person*>::iterator it = People.begin(); it != People.end();
it++)
{
std::cout << People[i]->GetPersonsPets() << std::endl;
i++;
}
//delete fluffy;
delete alice;
delete peter;
}
一切似乎都正常工作,但当涉及到删除宠物对象时,会发生一些有趣的事情。当我取消对delete fluffy
的注释时,floffy会在peter之后自动删除。
我想,既然蓬松是动态创建的,除非我自己做,否则它永远不会被破坏?
但当我不取消对delete fluffy
的注释时,会发生另一件有趣的事情。然后它的析构函数将被调用两次。
怎么可能两次毁掉一件东西?
在此处添加宠物时:
peter->AddPet(*fluffy);
则CCD_ 3是被引用的指针
void Person::AddPet(Pet& pet)
{
Pets.push_back(pet);
}
您将*fluffy
的副本存储在某个容器中(我想它是std::vector
(。
你看到的被破坏的对象是那些副本(向量管理自己的内存,即当向量被破坏时,它会破坏其元素(。您仍然需要删除在main
中创建的动态分配实例。
请注意,此处最好不要使用new
和delete
。必要时使用动态内存。当你这样做的时候,你最好使用智能指针,而不是原始指针。
PS您的代码表现出编写getter的糟糕做法,仅仅是因为。Pet
和Person
的所有成员都是公共的。将成员设为私有成员或删除getters
。两者兼而有之是误导。此外,如果您确实提供了默认构造函数(Pet() { }
(,它应该将成员初始化为有意义的值。构造函数的工作是构造一个处于有效状态的对象。最后但同样重要的是,您应该像在中那样使用构造函数的成员初始值设定项列表
Pet(std::string name, std::string type) : Name(name),Type(type) {}
Pets.push_back(pet);
创建pet
的副本并将其存储在向量中。当矢量被销毁时,该副本被销毁(但分配有new
的原始fluffy
仍然泄漏(。
取消对delete fluffy;
的注释时,可以正确地销毁原始对象及其副本。
如果您想跟踪创建的对象的副本,请添加用户定义的副本构造函数和副本赋值运算符(阅读"三条规则"(。
请记住,进入容器的是您指定的对象的副本。在您的情况下,对象*fluffy
的副本将进入容器。被销毁的是这个副本(因此调用其析构函数(,而不是在行Pet* fluffy = new Pet("Flyffy", "dog");
中创建的原始新对象。因此,使用//delete fluffy;
的代码会导致内存泄漏。
如果您考虑将指针本身复制到容器中,请注意,当使用新指针的容器时,请记住在销毁容器之前删除指针(Item 7,Effective STL,Scott Meyers。(,因为销毁指针对象不会调用delete。或者使用@formerlyknownas_463035818 提到的智能指针
- 我的神经网络不起作用 [XOR 问题]
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- C++为什么尽管我调用了void函数,它却不起作用
- 为什么在保护模式下继承升级不起作用
- 循环在计数器中不起作用
- 在其他文件中创建类时在 c++ 项目中不起作用
- Visual studio代码重构似乎不起作用(例如,重命名符号-f2)
- 为什么二进制搜索在我的测试中不起作用
- 我的代码中有错误吗?使用BGI图形的C++代码对我不起作用
- 为什么 const std::p air<K,V>& 在 std::map 上基于范围的 for 循环不起作用?
- 带有指定长度字符* 参数的 std::regex_search 在 VS2017 中不起作用?
- Bjarne Stroustrup Book - std_lib_facilities.h - 不起作用(未知类型名称)
- 为什么简单的算术减法在"if"条件下不起作用?
- 为什么Stroustup书中的has_f不起作用
- 你能检查一下为什么在这个代码中从链接列表中删除项目不起作用吗
- 嵌套While循环不起作用(C++问题)
- C++Matching Brackets 2解决方案不起作用
- 动态记忆的删除是如何真正起作用的
- Minimax算法如何真正起作用