Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Segmentation fault



  • Hello,

    I have a segmentation fault that I really don't understand even with the debugger, I know where the problem is but I can't see what's the problem at all xD

    To resume :
    I have two pokemons of the class Pokemon
    Those pokemons have four capacities :

    Capacity *m_capacity_1;
    Capacity *m_capacity_2;
    Capacity *m_capacity_3;
    Capacity *m_capacity_4;
    

    And one active capacity :

    Capacity *m_active_capacity;
    

    After creating my two pokemons, I want the first one to attack the second so I have some functions in my class Pokemon :

    Capacity* Pokemon::get_active_capacity() const
    {
        return m_active_capacity;
    }
    
    void Pokemon::set_active_capacity(Capacity const& capacity)
    {
        delete m_active_capacity;
        m_active_capacity = new Capacity(capacity); //Calling the copy constructor that works well
    }
    

    And before attacking I set the active_capacity of the attacker because it's the one he's gonna use :

    pokemon_1->set_active_capacity(*(pokemon_1->get_capacity(1)));
    

    And this works BUT the problem I have is that I want to do the above command when I click on the capacity button so I created a connection with my button :

    QObject::connect(m_button_capacity_1, &QPushButton::released, this, [=]() { pokemon_1->set_active_capacity(*(pokemon_1->get_capacity(1)));  });
    

    The thing that I don't understand is that this line works if I call it directly in my code but if I try to call it in the connect above, it create a segmentation fault :/

    Any idea ? :)



  • @Tequiloutre said in Segmentation fault:

    BUT if I call it in a connect function like this :

    QObject::connect(m_button_capacity_1, &QPushButton::released, this, [=]() { pokemon_1->set_active_capacity(*(pokemon_1->get_capacity(1))) ; });
    

    I get a segmentation fault.

    How is pokemon_1 allocated? Is it possible that it has been destroyed or moved by the time the button has been clicked?



  • @Tequiloutre
    Verify what pokemon_1 and pokemon_1->get_capacity(1) return in your lambda. And look at what the stack trace is showing you in the debugger --- you can even go up levels and see the value of stuff there. And/or, put breakpoints in the methods you show.



  • @JonB

    Indeed, it seems to have a problem in the lambda.
    I've just asked to qDebug pokemon_1 in the connect, and I get it but all the values are wrong :

    		pokemon_1	@0x5555559e1050	Pokemon
    			m_active_capacity	@0x5555559f0000	Capacity
    			m_att	3145776	int
    			m_att_spe	3145783	int
    			m_capacity_1	0x30003200370064	Capacity*
    			m_capacity_2	0x30003000300030	Capacity*
    			m_capacity_3	0x30003000330038	Capacity*
    			m_capacity_4	0x30003000300030	Capacity*
    			m_def	3145776	int
    			m_def_spe	3145776	int
    			m_etat	<inaccessible>	QString
    			m_ev_att	3145776	int
    			m_ev_att_spe	3145776	int
    			m_ev_def	3145776	int
    			m_ev_def_spe	3145777	int
    			m_ev_hp	3145776	int
    			m_ev_vit	3145776	int
    			m_gender	<inaccessible>	QString
    			m_hp	2293805	int
    			m_hpMax	6684774	int
    			m_id	1	int
    			m_iv_att	3145776	int
    			m_iv_att_spe	3145776	int
    			m_iv_def	3145776	int
    			m_iv_def_spe	3145776	int
    			m_iv_hp	3145776	int
    			m_iv_vit	3145776	int
    			m_lvl	7209071	int
    			m_name	<inaccessible>	QString
    			m_nature	<inaccessible>	QString
    			m_type_1	<inaccessible>	QString
    			m_type_2	<inaccessible>	QString
    			m_vit	3145776	int
    

    But I can't understand why ?
    Why does the lambda doesn't get the right values ? :o



  • @Tequiloutre said in Segmentation fault:

    Those pokemons have four capacities :
    Capacity *m_capacity_1;
    Capacity *m_capacity_2;
    Capacity *m_capacity_3;
    Capacity *m_capacity_4;

    And one active capacity :
    Capacity *m_active_capacity;

    Maybe there is a reason why you do this, but I would re-design this structure and create one container with all four capacities and add a bool isActive to Capacity class.

    You can get your active one by iterating the container and check the active state at the same time. Then just return the active one.



  • @Pl45m4

    Thank you for your advice but in the end I would still have to use a function in my connect to recover the capacity, and I would come back to the same problem, right ?

    I think I've understand wrong the debugger, I've watched the values at the beginning of my app, just after the creation of the pokemon_1 and the values showed in the debugger are wrong too but if I print the values in the console with my functions they're right. So I just don't understand the debugger xD

    But the problem seems to be

    void Pokemon::set_active_capacity(Capacity const& capacity)
    {
        delete m_active_capacity; //<= this line
        m_active_capacity = new Capacity(capacity);
    }
    

    The thing that I really don't understand is why those commands works when called in main window but not when called in connect function ?

    Debugger stack traces (don't know if it helps) :

    1 std::__atomic_base<int>::load
    2 QAtomicOps<int>::loadRelaxed<int>
    3 QBasicAtomicInteger<int>::loadRelaxed
    4 QPrivate::RefCount::deref
    5 QString::~QString
    6 Capacity::~Capacity
    7 Pokemon::set_active_capacity
    8 Window::<lambda()>::operator()(void) const
    ...
    

  • Lifetime Qt Champion

    Then don't delete the old pointer here and simply assign the value. Maybe don't even store a pointer but an object as member.



  • @Christian-Ehrlicher

    I change some things as you advised :

    void Pokemon::set_active_capacity(Capacity* capacity)
    {
        m_active_capacity = capacity;
    }
    

    Then I call it with the button connect like this :

    QObject::connect(m_button_capacity_1, &QPushButton::released, this, [=]() { pokemon_1->set_active_capacity(pokemon_1->get_capacity(1)) ; });
    

    And it seems to work BUT I think it just gets around the problem because I have the same segmentation fault just after that with the simple command :

    pokemon_1->get_name();
    

    I think the reason is just that I don't use the lambda (that I really don't know much) correctly because as I said before, all of the Pokemon class functions works well when called directly in the program but doesn't work when called in the connect function.

    For exemple :

    qDebug() << "pokemon_1.active_capacity : " << pokemon_1->get_active_capacity()->get_name();
    pokemon_1->set_active_capacity(*(pokemon_1->get_capacity(1)));
    qDebug() << "pokemon_1.active_capacity : " << pokemon_1->get_active_capacity()->get_name();
    

    Returns :

    pokemon_1.active_capacity : /*Nothing because I create it with an empty name in the Pokemon constructor*/
    pokemon_1.active_capacity : Charge /*The name of pokemon_1.capacity_1 because the set_active_capacity() worked*/
    

    BUT if I call it in a connect function like this :

    QObject::connect(m_button_capacity_1, &QPushButton::released, this, [=]() { pokemon_1->set_active_capacity(*(pokemon_1->get_capacity(1))) ; });
    

    I get a segmentation fault.



  • @Tequiloutre said in Segmentation fault:

    BUT if I call it in a connect function like this :

    QObject::connect(m_button_capacity_1, &QPushButton::released, this, [=]() { pokemon_1->set_active_capacity(*(pokemon_1->get_capacity(1))) ; });
    

    I get a segmentation fault.

    How is pokemon_1 allocated? Is it possible that it has been destroyed or moved by the time the button has been clicked?


  • Lifetime Qt Champion

    @Tequiloutre said in Segmentation fault:

    I change some things as you advised :

    I did not said this:

    and simply assign the value.

    The value of the object, not the value of the pointer



  • @jeremy_k

    pokemon_1 is allocated like this :

    Pokemon *pokemon_1 = new Pokemon(tortipouss, 5, charge, repli);
    

    It gets the basic values of tortipouss and calculate all the stats at lvl 5 and give it the capacities charge and repli, all declared before it like this :

    Capacity charge("Charge", "NORMAL", "PHY", 35, 95, 35, 35, 0);
    Capacity repli("Repli", "EAU", "STA", 0, 0, 40, 40, 0);
    
    Init_Pokemon tortipouss(387, "Tortipouss", "PLANTE", "", 55, 68, 64, 45, 55, 31, 12.5, 87.5);
    

    Then values of pokemon_1 looks like this :

    m_id :  387
    m_name :  "Tortipouss"
    m_type_1 :  "PLANTE"
    m_type_2 :  ""
    m_gender :  "♂"
    m_lvl :  5
    m_hp :  21
    m_hp_max :  21
    m_etat :  ""
    m_nature :  ""
    m_iv_hp :  18
    m_iv_att :  8
    m_iv_def :  30
    m_iv_att_spe :  16
    m_iv_def_spe :  3
    m_iv_vit :  9
    m_ev_hp :  0
    m_ev_att :  0
    m_ev_def :  0
    m_ev_att_spe :  0
    m_ev_def_spe :  0
    m_ev_vit :  0
    m_att :  12
    m_def :  12
    m_att_spe :  10
    m_def_spe :  10
    m_vit :  8
    m_capacity_1->get_name() :  "Charge"
    m_capacity_2->get_name() :  "Repli"
    m_capacity_3->get_name() :  ""
    m_capacity_4->get_name() :  ""
    m_active_capacity->get_name() :  ""
    

    I get all those values with simple : qDebug() << "m_name : " << pokemon_1->get_name();
    .
    .
    @Christian-Ehrlicher

    You mean like this ?

    void Pokemon::set_active_capacity(Capacity const& capacity)
    {
        *m_active_capacity = capacity;
    }
    

    I completely changed my program to use m_active_capacity as an object instead of a pointer and finally :
    Segmentation fault with the operator= function :

    Capacity& Capacity::operator=(Capacity const& copy)
    {
        if (this != &copy) {
            m_name = copy.m_name;
            m_type = copy.m_type;
            m_category = copy.m_category;
            m_power = copy.m_power;
            m_aim = copy.m_aim;
            m_pp = copy.m_pp;
            m_pp_max = copy.m_pp_max;
            m_priority = copy.m_priority;
        }
        return *this;
    }
    


  • OW FFS I hate myself.

    @jeremy_k were right.

    I'm a beginner with Qt and I've made a stupid mistake.

    I told myself "Hey you're creating pokemon_1 as a new pointer so you dynamicaly allocate some memory that have to be freeded at the end of the program haha"

    I had those lines at the end of my main_window class definition :

    delete pokemon_1;
    delete pokemon_2;
    

    OF COURSE they're destroyed before I press the button !

    SO SORRY about that guys, thank you very much for your time and advices !


Log in to reply