C++ 内存泄漏问题与我的代码,我是新手
我不断得到一个内存泄漏,这似乎是因为新的初始化对象作为指针传递给添加…实际上不是删除。但不知何故,我无法使它正常工作。我尝试添加一个for循环来循环Monsters类中数组中的每个对象,以便在调用析构函数时删除每个对象。然后删除[]个怪物;和怪物=空PTR 在析构函数中运行此代码时发生:C++ 内存泄漏问题与我的代码,我是新手,c++,C++,我不断得到一个内存泄漏,这似乎是因为新的初始化对象作为指针传递给添加…实际上不是删除。但不知何故,我无法使它正常工作。我尝试添加一个for循环来循环Monsters类中数组中的每个对象,以便在调用析构函数时删除每个对象。然后删除[]个怪物;和怪物=空PTR 在析构函数中运行此代码时发生: 有两个地方代码会泄漏内存 MonstersList* InitListOfMonsters() { // ... monsters->add(new Monster("Sally
有两个地方代码会泄漏内存
MonstersList* InitListOfMonsters()
{
// ...
monsters->add(new Monster("Sally"));
// ...
return monsters;
}
每一条新闻都分配了永远不会释放的内存。由于您不存储指针,而是存储怪物对象,因此您不应该传递指针,而应该传递怪物
并修改添加为
我看到的第二个,主要是
没有相应的
delete monsters;
在销毁对象之前,不会执行析构函数。
当你调用删除怪物时,就会发生这种情况
更新以进行编辑
该代码有两个问题
if (monsters != nullptr) {
for (Monster* m = begin(); m != end(); m++) {
delete m;
}
delete[] monsters;
monsters = nullptr;
}
该循环相当于
for (Monster* m = monsters; m != (monsters + total); m++) {
delete m;
}
第一次删除是删除怪物,它会删除整个阵列,并与后面的delete[]怪物进行双重删除。
此外,它还删除了以下元素,这些元素不是单独分配的,而是在第一次迭代中已删除的整个数组的一部分
第二个问题是。简单的delete用于单个对象,而delete[]用于动态分配的数组。在这种情况下,for中的第一个delete m使用非数组delete删除一个数组
最后,注意评论中的建议和警告。
当你使用C++,特别是C++ 11和更新的时候,用C++的方式来做。如果确实需要指针,请使用vector和unique_ptr。有两个地方代码会泄漏内存
MonstersList* InitListOfMonsters()
{
// ...
monsters->add(new Monster("Sally"));
// ...
return monsters;
}
每一条新闻都分配了永远不会释放的内存。由于您不存储指针,而是存储怪物对象,因此您不应该传递指针,而应该传递怪物
并修改添加为
我看到的第二个,主要是
没有相应的
delete monsters;
在销毁对象之前,不会执行析构函数。
当你调用删除怪物时,就会发生这种情况
更新以进行编辑
该代码有两个问题
if (monsters != nullptr) {
for (Monster* m = begin(); m != end(); m++) {
delete m;
}
delete[] monsters;
monsters = nullptr;
}
该循环相当于
for (Monster* m = monsters; m != (monsters + total); m++) {
delete m;
}
第一次删除是删除怪物,它会删除整个阵列,并与后面的delete[]怪物进行双重删除。
此外,它还删除了以下元素,这些元素不是单独分配的,而是在第一次迭代中已删除的整个数组的一部分
第二个问题是。简单的delete用于单个对象,而delete[]用于动态分配的数组。在这种情况下,for中的第一个delete m使用非数组delete删除一个数组
最后,注意评论中的建议和警告。
当你使用C++,特别是C++ 11和更新的时候,用C++的方式来做。如果确实需要指针,请使用vector和unique_ptr。好的,这是我以前的努力。请参阅代码中不同点的注释,了解您缺少的内容 参考资料 知道这些很好,尽管这并不意味着你应该是个老派。现代C++更好。
#include <iostream>
#include <algorithm>
#include <string>
class Monster
{
public:
Monster() {};
Monster(std::string name) : name(name) {}
private:
std::string name = "";
};
class MonstersList
{
public:
MonstersList(int max) : monsters(new Monster[max]), max(max), total(0)
{
}
// copy constructor, essential if your destructor deletes, see rule of three
MonstersList(const MonstersList& rhs) : monsters(new Monster[rhs.max]), max(rhs.max), total(rhs.total)
{
std::copy(rhs.begin(), rhs.end(), begin());
}
// assignment operator, again essential with a deleting destructor,
// this implementation uses the copy and swap idiom
MonstersList& operator=(MonstersList rhs)
{
swap(rhs);
return *this;
}
virtual ~MonstersList()
{
delete[] monsters;
}
void swap(MonstersList& rhs)
{
std::swap(monsters, rhs.monsters);
std::swap(max, rhs.max);
std::swap(total, rhs.total);
}
void add(const Monster& m) // pass by reference
{
monsters[total++] = m;
}
Monster* begin() const { return monsters; }
Monster* end() const { return monsters + total; }
private:
Monster* monsters;
int max;
int total;
};
MonstersList* InitListOfMonsters()
{
// allocate a list of monsters, but no need to allocate the monsters themselves
MonstersList* monsters = new MonstersList(2);
monsters->add(Monster("Sally"));
monsters->add(Monster("Rich"));
return monsters;
}
int main()
{
MonstersList* monsters = InitListOfMonsters();
// Do something here...
// don't forget to delete the monster list
delete monsters;
return 0;
}
好吧,这是我以前的努力。请参阅代码中不同点的注释,了解您缺少的内容 参考资料 知道这些很好,尽管这并不意味着你应该是个老派。现代C++更好。
#include <iostream>
#include <algorithm>
#include <string>
class Monster
{
public:
Monster() {};
Monster(std::string name) : name(name) {}
private:
std::string name = "";
};
class MonstersList
{
public:
MonstersList(int max) : monsters(new Monster[max]), max(max), total(0)
{
}
// copy constructor, essential if your destructor deletes, see rule of three
MonstersList(const MonstersList& rhs) : monsters(new Monster[rhs.max]), max(rhs.max), total(rhs.total)
{
std::copy(rhs.begin(), rhs.end(), begin());
}
// assignment operator, again essential with a deleting destructor,
// this implementation uses the copy and swap idiom
MonstersList& operator=(MonstersList rhs)
{
swap(rhs);
return *this;
}
virtual ~MonstersList()
{
delete[] monsters;
}
void swap(MonstersList& rhs)
{
std::swap(monsters, rhs.monsters);
std::swap(max, rhs.max);
std::swap(total, rhs.total);
}
void add(const Monster& m) // pass by reference
{
monsters[total++] = m;
}
Monster* begin() const { return monsters; }
Monster* end() const { return monsters + total; }
private:
Monster* monsters;
int max;
int total;
};
MonstersList* InitListOfMonsters()
{
// allocate a list of monsters, but no need to allocate the monsters themselves
MonstersList* monsters = new MonstersList(2);
monsters->add(Monster("Sally"));
monsters->add(Monster("Rich"));
return monsters;
}
int main()
{
MonstersList* monsters = InitListOfMonsters();
// Do something here...
// don't forget to delete the monster list
delete monsters;
return 0;
}
std::unique_ptr monsters=InitListOfMonsters;怪物名单!=怪物!=Monster,如果这段代码真的在Visual Studio中编译,我没有可用的测试工具,那么您应该使用更可靠的工具。@AlbinM,但是,我用的是老派的方法。-传统的方法要求您了解用户定义的复制构造函数、赋值运算符等。仅使用new[]和delete[]所学到的东西很少。要真正修复您的类,需要付出比您想象的更多的努力。是的,您的函数是错误的。还不清楚为什么要传递一个指向add的指针而不是一个引用。结合代码中的所有其他问题,你应该知道为什么推荐编写现代C++代码的方法是使用STD::矢量和智能指针,而不是手动管理这样的内存,一般避免写新的和删除。@ Albimm,在这个点上,答案很可能是对你正在做的事情的彻底改写。这不是一件可以在这里或那里调整的事情。正如我所说的,如果你想以传统的方式做事,那么要让你的代码真正工作并可用,需要比你想象的多得多的工作;怪物名单!=怪物!=Monster,如果这段代码真的在Visual Studio中编译,我没有可用的测试工具,那么您应该使用更可靠的工具。@AlbinM,但是,我用的是老派的方法。-传统的方法要求您了解用户定义的复制构造函数、赋值运算符等,只有我们知道
对new[]和delete[]进行初始化所起的作用很小。要真正修复您的类,需要付出比您想象的更多的努力。是的,您的函数是错误的。还不清楚为什么要传递一个指向add的指针而不是一个引用。结合代码中的所有其他问题,你应该知道为什么推荐编写现代C++代码的方法是使用STD::矢量和智能指针,而不是手动管理这样的内存,一般避免写新的和删除。@ Albimm,在这个点上,答案很可能是对你正在做的事情的彻底改写。这不是一件可以在这里或那里调整的事情。正如我所说的,如果你想用传统的方式来做事情,那么要让你的代码真正工作并可用,需要比你想象的多得多的工作。没有相应的工作,因为我希望执行析构函数。这就是为什么,指针没有析构函数。见更新的答案。奥拉夫,假设怪物*m=新怪物萨利;然后是怪物->添加;即使add引用,这仍然有效吗?@AlbinM析构函数不是自动的裸动态分配。动态分配的自动销毁需要一个自动看门狗,即智能指针,如果您必须使用动态分配,它应该是强制性的,但只有在您确定您首先甚至需要手动动态分配之后,不管你做还是不做,可能性都很大。你似乎来自其他语言,在这些语言中,经常使用new,甚至需要创建对象。然而,C++中的情况并非如此。在现代C++中,几乎不需要或应该使用裸的新的或裸的指针。特别是当你是C++新手时,我建议不要使用原始指针,但是要坚持使用智能指针和标准容器。没有相应的原因,因为我希望执行析构函数。这就是为什么,指针没有析构函数。见更新的答案。奥拉夫,假设怪物*m=新怪物萨利;然后是怪物->添加;即使add引用,这仍然有效吗?@AlbinM析构函数不是自动的裸动态分配。动态分配的自动销毁需要一个自动看门狗,即智能指针,如果您必须使用动态分配,它应该是强制性的,但只有在您确定您首先甚至需要手动动态分配之后,不管你做还是不做,可能性都很大。你似乎来自其他语言,在这些语言中,经常使用new,甚至需要创建对象。然而,C++中的情况并非如此。在现代C++中,几乎不需要或应该使用裸的新的或裸的指针。特别是当你是C++新手时,我建议不要使用原始指针,而是要使用智能指针和标准容器。怪物->加法{莎丽};怪物->添加{Rich};-看起来好多了,我想。@PaulMcKenzie是的,看起来不错,我还得适应制服initialisation@john,这不适用于Monster*m=新怪物Sally;然后是怪物->添加@当然不会,但是当你的怪物列表类存储怪物而不是怪物指针时,没有理由分配怪物对象。因此,上面的代码是一种改进。如果你想分配怪物对象,那么你需要改变你的MisturistC类来存储怪物指针。@ AlbinM——正如另一个评论所建议的,你似乎误解了C++需要新创建对象。事实并非如此。怪物->添加{Sally};怪物->添加{Rich};-看起来好多了,我想。@PaulMcKenzie是的,看起来不错,我还得适应制服initialisation@john,这不适用于Monster*m=新怪物Sally;然后是怪物->添加@当然不会,但是当你的怪物列表类存储怪物而不是怪物指针时,没有理由分配怪物对象。因此,上面的代码是一种改进。如果你想分配怪物对象,那么你需要改变你的MisturistC类来存储怪物指针。@ AlbinM——正如另一个评论所建议的,你似乎误解了C++需要新创建对象。事实并非如此。
#include <iostream>
#include <algorithm>
#include <string>
class Monster
{
public:
Monster() {};
Monster(std::string name) : name(name) {}
private:
std::string name = "";
};
class MonstersList
{
public:
MonstersList(int max) : monsters(new Monster[max]), max(max), total(0)
{
}
// copy constructor, essential if your destructor deletes, see rule of three
MonstersList(const MonstersList& rhs) : monsters(new Monster[rhs.max]), max(rhs.max), total(rhs.total)
{
std::copy(rhs.begin(), rhs.end(), begin());
}
// assignment operator, again essential with a deleting destructor,
// this implementation uses the copy and swap idiom
MonstersList& operator=(MonstersList rhs)
{
swap(rhs);
return *this;
}
virtual ~MonstersList()
{
delete[] monsters;
}
void swap(MonstersList& rhs)
{
std::swap(monsters, rhs.monsters);
std::swap(max, rhs.max);
std::swap(total, rhs.total);
}
void add(const Monster& m) // pass by reference
{
monsters[total++] = m;
}
Monster* begin() const { return monsters; }
Monster* end() const { return monsters + total; }
private:
Monster* monsters;
int max;
int total;
};
MonstersList* InitListOfMonsters()
{
// allocate a list of monsters, but no need to allocate the monsters themselves
MonstersList* monsters = new MonstersList(2);
monsters->add(Monster("Sally"));
monsters->add(Monster("Rich"));
return monsters;
}
int main()
{
MonstersList* monsters = InitListOfMonsters();
// Do something here...
// don't forget to delete the monster list
delete monsters;
return 0;
}