CPP中的Valgrind和内存泄漏:“有条件的跳转或移动取决于未初始化的值”

丹尼尔

该代码将编译并运行,并创建预期的输出,除非运行valgrind时才会出现这些内存泄漏。以下代码在Visual Studio上运行,没有出现任何警告或错误。

所以我的问题是,此内存泄漏发生在哪里?我是CPP的新手,已经花了数小时的时间,所以这些错误让我感到惊讶。

就顺序而言,我有做错什么吗?我在某个地方传递未初始化的值吗?困惑。

我在弄清楚发生内存丢失的位置时遇到了麻烦。这些是文件:

/// Saiyan.cpp

#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <iostream>
#include "Saiyan.h"

using namespace std;

namespace sdds
{
    // CONSTRUCTORS:
    Saiyan::Saiyan()
    {
        // default state
        m_name = nullptr;   // Dynamic allocation:  set to nullptr!
        m_dob = 0;
        m_power = 0;
        m_super = false;
        m_level = 0;
    }
    
    Saiyan::Saiyan(const char* name, int dob, int power)
    {
        set(name, dob, power);
    }

    // MEMBER FUNCTIONS:
    void Saiyan::set(const char* name, int dob, int power, int level, bool super)
    {
        // Check if arguments are valid:
        if (name == nullptr || strlen(name) <= 0 || dob > 2020 || power <= 0)
        {
            *this = Saiyan();   // Calls constructor that creates default.
        }
        else
        {
            // Deallocate previosly allocated memory for m_name to avoid memory leak:
            if (m_name != nullptr && strlen(name) == 0)
            {
                delete[] m_name;
                m_name = nullptr;
            }
            // Assign validate values to current object:
            m_name = new char[strlen(name) + 1];
            strcpy(m_name, name);
            m_dob = dob;
            m_power = power;
            m_super = super;
            m_level = level;
        }
    }
    
    bool Saiyan::isValid() const
    {
        bool valid_state = m_name != nullptr && strlen(m_name) > 0 && m_dob < 2020 && m_power > 0;
        return valid_state;
    }

    void Saiyan::display() const
    {
        if (isValid())
        {
            cout << m_name << endl;
            
            cout.setf(ios::right);
            cout.width(10);
            cout << "DOB: " << m_dob << endl;
            cout.width(10);
            cout << "Power: " << m_power << endl;
            cout.width(10);
            if (m_super == true) {
                cout << "Super: " << "yes" << endl;
                cout.width(10);
                cout << "Level: " << m_level;
            }
            else
            {
                cout << "Super: " << "no";
            }
            cout.unsetf(ios::left);
        }
        else
        {
            cout << "Invalid Saiyan!";
        }
        cout << endl;
    }

    bool Saiyan::fight(Saiyan& other)
    {
        // Check both Saiyans for super level and power up accordingly:
        if (m_super == true)
        {
            m_power += int(m_power * (.1 * m_level));   // Cast an int to avoid possible memory loss.
        }
        if (other.m_super == true)
        {
            other.m_power += int(other.m_power * (.1 * other.m_level));
        }

        bool value = m_power > other.m_power;
        return value;
    }

    // DESTRUCTOR:
    Saiyan::~Saiyan()
    {
        if (m_name != nullptr)
        {
            delete[] m_name;    // Deallocate memory of member.
            m_name = nullptr;
        }
    }
}



// Saiyan.h

#pragma once
#ifndef SDDS_SAIYAN_H
#define SDDS_SAIYAN_H

namespace sdds
{
    class Saiyan
    {
        char* m_name;       // Dynamically allocated array of chars.
        int m_dob;          // Year the Saiyan was born.
        int m_power;        // Integer indicating the strength of the Saiyan (>= 0).
        bool m_super;       // indicates whether Saiyan can evolve
        int m_level;        // an integer indicating the level of a SS

        /*
        ***Valid Name*** : a dynamically allocated array of chars.
        ***Valid Year of Birth***: an integer within the interval[0, 2020].
        ***Valid Power***: an integer that is greater than 0.
        */

    public:
        Saiyan();
        Saiyan(const char* name, int dob, int power);  // Custom constructor
        void set(const char* name, int dob, int power, int level = 0, bool super = false);
        bool isValid() const;
        void display() const;
        bool fight(Saiyan& other);  // Fight and power up Saiyans.
        ~Saiyan();
    };
}

#endif



// main.cpp

#include <iostream>
#include "Saiyan.h"
#include "Saiyan.h"  // this is on purpose

using namespace std;
using namespace sdds;

void printHeader(const char* title)
{
    char oldFill = cout.fill('-');
    cout.width(40);
    cout << "" << endl;

    cout << "|> " << title << endl;

    cout.fill('-');
    cout.width(40);
    cout << "" << endl;
    cout.fill(oldFill);
}


int main()
{
    {
        printHeader("T1: Checking default constructor");

        Saiyan theSayan;
        theSayan.display();
        cout << endl;
    }

    {
        printHeader("T2: Checking custom constructor");

        Saiyan army[] = {
          Saiyan("Nappa", 2025, 1),
          Saiyan("Vegeta", 2018, -1),
          Saiyan("Goku", 1990, 200),
          Saiyan(nullptr, 2015, 1),
          Saiyan("", 2018, 5)
        };

        cout << "Only #2 should be valid:" << endl;
        for (int i = 0; i < 5; i++)
        {
            cout << "  Sayan #" << i << ": " << (army[i].isValid() ? "valid" : "invalid") << endl;
        }
        for (int i = 0; i < 5; i++)
        {
            army[i].display();
        }
        cout << endl;
    }

    // valid saiyans
    Saiyan s1("Goku", 1990, 2000);
    Saiyan s2;
    s2.set("Vegeta", 1989, 2200);

    {
        printHeader("T3: Checking the fight");
        s1.display();
        s2.display();

        cout << "S1 attacking S2, Battle " << (s1.fight(s2) ? "Won" : "Lost") << endl;
        cout << "S2 attacking S1, Battle " << (s2.fight(s1) ? "Won" : "Lost") << endl;
        cout << endl;
    }

    {
        printHeader("T4: Checking powerup");
        s1.set("Goku", 1990, 1900, 1, true);
        int round = 0;
        bool gokuWins = false;
        while (!gokuWins) // with every fight, the super saiyan should power up
        {
            cout << "Round #" << ++round << endl;
            gokuWins = s1.fight(s2);
            s1.display();
            s2.display();
        }

        cout << "Bonus round. Is s2 winning? " << (s2.fight(s1) ? "yes" : "no") << endl;
        s1.display();
        s2.display();
        cout << endl;
    }

    {
        printHeader("T5: Upgrading s2");
        s2.set("Vegeta", 1990, 2200, 3, true);

        cout << "Super Battle. Is s2 winning? " << (s2.fight(s1) ? "yes" : "no") << endl;
        s1.display();
        s2.display();
        cout << endl;
    }
 
    return 0;
}

这是最终工作的结果:

/// Saiyan.cpp
#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <iostream>
#include "Saiyan.h"

using namespace std;

namespace sdds
{
    Saiyan::Saiyan()
    {
    }
    
    Saiyan::Saiyan(const char* name, int dob, int power)
    {
        set(name, dob, power);
    }

    void Saiyan::set(const char* name, int dob, int power, int level, bool super)
    {
        if (name != nullptr && name[0] != '\0')
        {
            if (m_name != nullptr)
            {
                delete[] m_name;
                m_name = nullptr;
            }
            m_name = new char[strlen(name) + 1];
            strcpy(m_name, name);
        }
        if (dob != 0 && dob < 2020)
        {
            m_dob = dob;
        }
        if (power > 0)
        {
            m_power = power;
        }
        if (level > 0)
        {
            m_level = level;
        }
        m_super = super;
    }
    
    bool Saiyan::isValid() const
    {
        bool valid_state = m_name != nullptr && m_dob != 0 && m_dob < 2020 && m_power > 0 && m_level >= 0;
        return valid_state;
    }

    void Saiyan::display() const
    {
        if (isValid())
        {
            cout << m_name << endl;
            
            cout.setf(ios::right);
            cout.width(10);
            cout << "DOB: " << m_dob << endl;
            cout.width(10);
            cout << "Power: " << m_power << endl;
            cout.width(10);
            if (m_super == true) {
                cout << "Super: " << "yes" << endl;
                cout.width(10);
                cout << "Level: " << m_level;
            }
            else
            {
                cout << "Super: " << "no";
            }
            cout.unsetf(ios::left);
        }
        else
        {
            cout << "Invalid Saiyan!";
        }
        cout << endl;
    }

    bool Saiyan::fight(Saiyan& other)
    {
        // Check both Saiyans for super level and power up accordingly:
        if (m_super == true)
        {
            m_power += int(m_power * (.1 * m_level));   // Cast an int to avoid possible memory loss.
        }
        if (other.m_super == true)
        {
            other.m_power += int(other.m_power * (.1 * other.m_level));
        }

        bool value = m_power > other.m_power;
        return value;
    }

    Saiyan::~Saiyan()
    {
        if (m_name != nullptr)
        {
            delete[] m_name;    // Deallocate memory of member.
            m_name = nullptr;
        }
    }
}



// Saiyan.h
#pragma once
#ifndef SDDS_SAIYAN_H
#define SDDS_SAIYAN_H

namespace sdds
{
    class Saiyan
    {
        char* m_name{};     // Dynamically allocated array of chars.
        int m_dob{};                // Year the Saiyan was born.
        int m_power{};          // Integer indicating the strength of the Saiyan (>= 0).
        bool m_super{};     // indicates whether Saiyan can evolve
        int m_level{};          // an integer indicating the level of a SS

        /*
        ***Valid Name*** : a dynamically allocated array of chars.
        ***Valid Year of Birth***: an integer within the interval[0, 2020].
        ***Valid Power***: an integer that is greater than 0.
        */

    public:
        Saiyan();
        Saiyan(const char* name, int dob, int power);  // Custom constructor
        void set(const char* name, int dob, int power, int level = 0, bool super = false);
        bool isValid() const;
        void display() const;
        bool fight(Saiyan& other);  // Fight and power up Saiyans.
        ~Saiyan();
    };
}

#endif
Slimak

通常---避免手动内存管理,为什么不只使用std :: string?

关于代码中的问题。

这部分代码很重要:

        if (name == nullptr || strlen(name) <= 0 || dob > 2020 || power <= 0)
        {
            *this = Saiyan();   // Calls constructor that creates default.
        }

实际上,您实际上是在这里绕过析构函数,因此,如果初始化了m_name,则会泄漏内存。

另一个问题是在此构造函数中:

    Saiyan::Saiyan(const char* name, int dob, int power)
    {
        set(name, dob, power);
    }

您不能确保始终在调用此构造函数后确保对象处于良好状态。

最后但并非最不重要的是,在这里:

            if (m_name != nullptr && strlen(name) == 0)
            {
                delete[] m_name;
                m_name = nullptr;
            }

仅当新名称简短时才取消分配m_name,但是无论新名称长度如何都应取消分配,因为您要将新值设置为m_name而不考虑新名称长度。

同样在C ++ 11中,您可以为构造函数外部的成员提供默认值,并且它们将在每个您没有显式设置其他值的构造函数中使用:

    class Saiyan
    {
        char* m_name = nullptr; // Dynamically allocated array of chars.
        int m_dob = 0;          // Year the Saiyan was born.
        int m_power = 0;        // Integer indicating the strength of the Saiyan (>= 0).
        bool m_super = false;   // indicates whether Saiyan can evolve
        int m_level = 0;        // an integer indicating the level of a SS

    public:
        Saiyan() {};
...

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

释放字符时,“有条件的跳转或移动取决于未初始化的值”

有条件的跳转或移动取决于未初始化的值和无效的大小写

Valgrind 消息:条件跳转或移动取决于未解析的未初始化值

fread() 导致 Valgrind 错误:“条件跳转或移动取决于未初始化的值”

查明“条件跳转或移动取决于未初始化的值” valgrind消息

条件跳转或移动取决于使用valgrind的未初始化值

错误:条件跳转或移动取决于未初始化的值-C valgrind

Valgrind + C:条件跳转或移动取决于未初始化的值

Valgrind:条件跳转或移动取决于未初始化的值-打开文件

Valgrind:使用哈希函数时,条件跳转或移动取决于未初始化的值

条件跳转或移动取决于未初始化的值

如何解决“有条件的跳跃或移动取决于未初始化的值” valgrind错误而导致的strlen错误?

条件跳转或移动取决于 for 循环中带有 strcat 的未初始化值

C ++中的动态数组-条件跳转或移动取决于未初始化的值

如何修复C中的“条件跳转或移动取决于未初始化的值”错误

二进制搜索树,Valgrind条件跳转或移动取决于未初始化的值

Valgrind:libnvidia-glcore.so.346.47条件跳转或移动取决于未初始化的值

Valgrind:使用atomic :: compare_exchange_weak时,条件跳转或移动取决于未初始化的值

条件跳转或移动取决于未初始化的值strcat

条件跳转或移动取决于std :: wistringstream的未初始化值

条件跳转或移动取决于 strcpy 处的未初始化值

Valgrind:条件跳转,未初始化的值,C ++基本代码

有条件的Ansible中的通知取决于角色

@有条件的bean初始化

数组初始化-有条件的

C - 链表 valgrind 未初始化错误取决于添加元素的顺序

如何有条件地格式化Kendo UI网格单元格(取决于值)

有条件地初始化JavaScript中的常量

有条件地使初始化列表中的shared_ptr为空