C++ 内存泄漏问题与我的代码,我是新手

C++ 内存泄漏问题与我的代码,我是新手,c++,C++,我不断得到一个内存泄漏,这似乎是因为新的初始化对象作为指针传递给添加…实际上不是删除。但不知何故,我无法使它正常工作。我尝试添加一个for循环来循环Monsters类中数组中的每个对象,以便在调用析构函数时删除每个对象。然后删除[]个怪物;和怪物=空PTR 在析构函数中运行此代码时发生: 有两个地方代码会泄漏内存 MonstersList* InitListOfMonsters() { // ... monsters->add(new Monster("Sally

我不断得到一个内存泄漏,这似乎是因为新的初始化对象作为指针传递给添加…实际上不是删除。但不知何故,我无法使它正常工作。我尝试添加一个for循环来循环Monsters类中数组中的每个对象,以便在调用析构函数时删除每个对象。然后删除[]个怪物;和怪物=空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。

有两个地方代码会泄漏内存

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;
}