簡體   English   中英

我如何解決 Glib::Timer::stop() 上的這個段錯誤?

[英]How do I solve this segfault on Glib::Timer::stop()?

下面是根據執行流程和一些 gdb output 的代碼,最相關的功能是來自 Time_Keeper 和 UI_Controller 的 start_timer,stop_timer 和 timeout_timer

ui-controller.h

#ifndef _U_I_CONTROLLER_H_
#define _U_I_CONTROLLER_H_

#include <unistd.h>
#include <gtkmm.h>
#include <unordered_map>
#include <glibmm/datetime.h>
#include <time-keeper.h>


namespace std{
    template <>
    struct hash<Time_Keeper>
    {
        size_t operator()( Time_Keeper& t) const
        {
            return t.hasheable().hash();
        }
    };
}

class UI_Controller
{
public:
    UI_Controller(Gtk::Builder* refference,Gtk::Application * app);
    void deffine_application(Gtk::Application * app);
    void add_window_to_application(Gtk::Window * window);
protected:

private:
    Gtk::Builder * refference;
    Gtk::ApplicationWindow * content_relations;
    Gtk::Application * app;
    std::vector<Glib::RefPtr<Glib::Object>> widgets;
    std::unordered_map<int,Time_Keeper> bind_time;
    void show_window(Gtk::Window *window);
    void start_timer(Gtk::Widget * selected, int position);
    void stop_timer(int i) { (bind_time[i]).stop_timer (); };
    void restart_timer(int i) { return ;}; // to be done
    void add_timer(int i) { return ;}; //to be done
    bool timeout_timer(Gtk::Label * display,int position);
};

#endif // _U_I_CONTROLLER_H_

ui-controller.cc

#include "u-i-controller.h"

UI_Controller::UI_Controller(Gtk::Builder * refference, Gtk::Application * app)
{
    deffine_application (app);
    this->refference = refference;
    refference->get_widget("main_window",this->content_relations);
    widgets = refference->get_objects();
    Glib::ustring widget_names = "";
    for (int i=0; i < widgets.size(); i++){
        widget_names = widget_names+dynamic_cast<Gtk::Widget*>(widgets.at(i).get())->get_name()+"\n";
        if (dynamic_cast<Gtk::Buildable*>(widgets.at(i).get())->get_name() == (Glib::ustring) "start_timer"){
            //dynamic_cast<Gtk::Widget*>(widgets.at(i).get())->get_ancestor(GTK_TYPE_BOX)
            //dynamic_cast<Gtk::Button*>(widgets.at(i).get())->signal_clicked().connect(sigc::mem_fun(*this,&Controlador_UI::botao_acionado));
            dynamic_cast<Gtk::Button*>(widgets.at(i).get())->signal_clicked().connect(sigc::bind<Gtk::Widget*>(sigc::mem_fun(*this,&UI_Controller::start_timer),dynamic_cast<Gtk::Widget*>(widgets.at(i).get()),i ) );
        }
        if (dynamic_cast<Gtk::Buildable*>(widgets.at(i).get())->get_name() == (Glib::ustring) "stop_timer"){
            dynamic_cast<Gtk::Button*>(widgets.at(i).get())->signal_clicked().connect(sigc::bind(sigc::mem_fun(*this,&UI_Controller::stop_timer),i ) );
        }
        if (dynamic_cast<Gtk::Buildable*>(widgets.at(i).get())->get_name() == (Glib::ustring) "restart_timer"){
            dynamic_cast<Gtk::Button*>(widgets.at(i).get())->signal_clicked().connect(sigc::bind(sigc::mem_fun(*this,&UI_Controller::restart_timer),i ) );
        }
        if (dynamic_cast<Gtk::Buildable*>(widgets.at(i).get())->get_name() == (Glib::ustring) "add_timer"){
            dynamic_cast<Gtk::Button*>(widgets.at(i).get())->signal_clicked().connect(sigc::bind(sigc::mem_fun(*this,&UI_Controller::add_timer),i ) );
        }
    }
    app->run();
}

void UI_Controller::deffine_application(Gtk::Application * app)
{
    this->app = app;
}

void UI_Controller::add_window_to_application (Gtk::Window * window)
{
    app->add_window(*window);
}

void UI_Controller::show_window(Gtk::Window * window)
{
    add_window_to_application(window);
    window->show();
    window->show_all_children();
}

void UI_Controller::start_timer(Gtk::Widget * selected, int position){
    if (bind_time.find(position) == bind_time.end() ){
        bind_time [position] = *(new Time_Keeper());
        (bind_time [position]).start_timer ();
    }
    Gtk::Label * display;
    refference->get_widget("timer_display",display);

    // both 2 variables bellow yet to be managed by this class

    sigc::slot<bool()> my_slot = sigc::bind(sigc::mem_fun(*this,
              &UI_Controller::timeout_timer), display, position);
    auto conn = Glib::signal_timeout().connect(my_slot, 100);
}

bool UI_Controller::timeout_timer(Gtk::Label * display,int position){
    if ( ((bind_time [position]).get_active()) ) display->set_text((bind_time [position]).display_timer ());
    return (bind_time [position]).get_active();
}

減少 Time_Keeper class

#ifndef _TIME_KEEPER_H_
#define _TIME_KEEPER_H_

#include <glibmm/datetime.h>
#include<memory>
#include <glibmm/timer.h>

class Time_Keeper
{
public:
    void start_timer();
    void stop_timer();
    // I would rather use the constructor, but I need a default one in order \
    to use the unordered list
    Glib::DateTime hasheable() { return Glib::DateTime::create_now_local(); }
    bool get_active() { return active; };
protected:

private:
    std::shared_ptr<Glib::Timer> timer;
    bool active = false;
};

#endif // _TIME_KEEPER_H_
#include "time-keeper.h"

void Time_Keeper::start_timer(){
    active = true;
    timer = std::shared_ptr<Glib::Timer>(new Glib::Timer);
    timer.get()->start(); 
};

void Time_Keeper::stop_timer(){
    active = false;
    timer.get()->stop();
}

主要的

#include <gtkmm.h>
#include <iostream>

#include "config.h"


#ifdef ENABLE_NLS
#  include <libintl.h>
#endif

#include "u-i-controller.h"

/* For testing propose use the local (not installed) ui file */
/* #define UI_FILE PACKAGE_DATA_DIR"/ui/time_keeper.ui" */
#define UI_FILE "src/time_keeper.ui"

Gtk::ApplicationWindow * main_win = 0;

void activate_app(Gtk::Application * app)
{
    app->add_window(*main_win);
    main_win->show();
    main_win->show_all_children ();
}

int
main (int argc, char *argv[])
{
    
    auto app = Gtk::Application::create(argc,argv,"org.gtkmm.time_keeper");

    //Load the Glade file and instiate its widgets:
    Glib::RefPtr<Gtk::Builder> builder;
    try
    {
        builder = Gtk::Builder::create_from_file(UI_FILE);
    }
    catch (const Glib::FileError & ex)
    {
        std::cerr << ex.what() << std::endl;
        return 1;
    }
    
    builder->get_widget("main_window", main_win);

    if (main_win)
    {
        app->signal_startup().connect(sigc::bind<Gtk::Application*>(sigc::ptr_fun(&activate_app), app.get() ) );
        UI_Controller * controller = new UI_Controller(builder.get(),app.get());
    }
}

time_keeper.ui

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
  <requires lib="gtk+" version="3.24"/>
  <object class="GtkApplicationWindow" id="main_window">
    <property name="can-focus">False</property>
    <child>
      <object class="GtkBox">
        <property name="visible">True</property>
        <property name="can-focus">False</property>
        <property name="orientation">vertical</property>
        <property name="spacing">13</property>
        <property name="homogeneous">True</property>
        <child>
          <object class="GtkBox">
            <property name="visible">True</property>
            <property name="can-focus">False</property>
            <property name="orientation">vertical</property>
            <child>
              <object class="GtkLabel">
                <property name="visible">True</property>
                <property name="can-focus">False</property>
                <property name="label" translatable="yes">current activity time</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkScrolledWindow">
                <property name="visible">True</property>
                <property name="can-focus">True</property>
                <property name="shadow-type">in</property>
                <child>
                  <object class="GtkViewport">
                    <property name="visible">True</property>
                    <property name="can-focus">False</property>
                    <child>
                      <!-- n-columns=4 n-rows=3 -->
                      <object class="GtkGrid" id="timer_grid">
                        <property name="visible">True</property>
                        <property name="can-focus">False</property>
                        <child>
                          <object class="GtkEntry">
                            <property name="visible">True</property>
                            <property name="can-focus">True</property>
                            <property name="hexpand">True</property>
                          </object>
                          <packing>
                            <property name="left-attach">0</property>
                            <property name="top-attach">0</property>
                            <property name="width">3</property>
                          </packing>
                        </child>
                        <child>
                          <object class="GtkButton" id="start_timer">
                            <property name="label" translatable="yes">Start</property>
                            <property name="visible">True</property>
                            <property name="can-focus">True</property>
                            <property name="receives-default">True</property>
                          </object>
                          <packing>
                            <property name="left-attach">0</property>
                            <property name="top-attach">2</property>
                          </packing>
                        </child>
                        <child>
                          <object class="GtkButton" id="stop_timer">
                            <property name="label" translatable="yes">Stop</property>
                            <property name="visible">True</property>
                            <property name="can-focus">True</property>
                            <property name="receives-default">True</property>
                          </object>
                          <packing>
                            <property name="left-attach">1</property>
                            <property name="top-attach">2</property>
                          </packing>
                        </child>
                        <child>
                          <object class="GtkButton" id="restart_timer">
                            <property name="label" translatable="yes">Restart</property>
                            <property name="visible">True</property>
                            <property name="can-focus">True</property>
                            <property name="receives-default">True</property>
                          </object>
                          <packing>
                            <property name="left-attach">2</property>
                            <property name="top-attach">2</property>
                          </packing>
                        </child>
                        <child>
                          <object class="GtkButton" id="add_timer">
                            <property name="label" translatable="yes">+</property>
                            <property name="visible">True</property>
                            <property name="can-focus">True</property>
                            <property name="receives-default">True</property>
                          </object>
                          <packing>
                            <property name="left-attach">3</property>
                            <property name="top-attach">0</property>
                            <property name="height">3</property>
                          </packing>
                        </child>
                        <child>
                          <object class="GtkLabel" id="timer_display">
                            <property name="visible">True</property>
                            <property name="can-focus">False</property>
                            <property name="hexpand">True</property>
                            <property name="vexpand">True</property>
                          </object>
                          <packing>
                            <property name="left-attach">0</property>
                            <property name="top-attach">1</property>
                            <property name="width">3</property>
                          </packing>
                        </child>
                      </object>
                    </child>
                  </object>
                </child>
              </object>
              <packing>
                <property name="expand">True</property>
                <property name="fill">True</property>
                <property name="position">1</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkBox">
            <property name="visible">True</property>
            <property name="can-focus">False</property>
            <property name="orientation">vertical</property>
            <child>
              <object class="GtkLabel">
                <property name="visible">True</property>
                <property name="can-focus">False</property>
                <property name="label" translatable="yes">activity limit</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkScrolledWindow">
                <property name="visible">True</property>
                <property name="can-focus">True</property>
                <property name="shadow-type">in</property>
                <child>
                  <object class="GtkViewport">
                    <property name="visible">True</property>
                    <property name="can-focus">False</property>
                    <child>
                      <!-- n-columns=4 n-rows=3 -->
                      <object class="GtkGrid">
                        <property name="visible">True</property>
                        <property name="can-focus">False</property>
                        <child>
                          <object class="GtkEntry">
                            <property name="visible">True</property>
                            <property name="can-focus">True</property>
                            <property name="hexpand">True</property>
                          </object>
                          <packing>
                            <property name="left-attach">0</property>
                            <property name="top-attach">0</property>
                            <property name="width">3</property>
                          </packing>
                        </child>
                        <child>
                          <object class="GtkButton">
                            <property name="label" translatable="yes">Start</property>
                            <property name="visible">True</property>
                            <property name="can-focus">True</property>
                            <property name="receives-default">True</property>
                          </object>
                          <packing>
                            <property name="left-attach">0</property>
                            <property name="top-attach">2</property>
                          </packing>
                        </child>
                        <child>
                          <object class="GtkButton">
                            <property name="label" translatable="yes">Stop</property>
                            <property name="visible">True</property>
                            <property name="can-focus">True</property>
                            <property name="receives-default">True</property>
                          </object>
                          <packing>
                            <property name="left-attach">1</property>
                            <property name="top-attach">2</property>
                          </packing>
                        </child>
                        <child>
                          <object class="GtkButton">
                            <property name="label" translatable="yes">Restart</property>
                            <property name="visible">True</property>
                            <property name="can-focus">True</property>
                            <property name="receives-default">True</property>
                          </object>
                          <packing>
                            <property name="left-attach">2</property>
                            <property name="top-attach">2</property>
                          </packing>
                        </child>
                        <child>
                          <object class="GtkButton">
                            <property name="label" translatable="yes">+</property>
                            <property name="visible">True</property>
                            <property name="can-focus">True</property>
                            <property name="receives-default">True</property>
                          </object>
                          <packing>
                            <property name="left-attach">3</property>
                            <property name="top-attach">0</property>
                            <property name="height">3</property>
                          </packing>
                        </child>
                        <child>
                          <object class="GtkLabel">
                            <property name="visible">True</property>
                            <property name="can-focus">False</property>
                            <property name="hexpand">True</property>
                            <property name="vexpand">True</property>
                          </object>
                          <packing>
                            <property name="left-attach">0</property>
                            <property name="top-attach">1</property>
                            <property name="width">3</property>
                          </packing>
                        </child>
                      </object>
                    </child>
                  </object>
                </child>
              </object>
              <packing>
                <property name="expand">True</property>
                <property name="fill">True</property>
                <property name="position">1</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

執行棧從gdb開始,黃線表示最后執行的代碼來自 gdb 的執行堆棧

根據 NoDakker 的回答,我發現了我的錯誤所在

if (dynamic_cast<Gtk::Buildable*>(widgets.at(i).get())->get_name() == (Glib::ustring) "stop_timer"){
            dynamic_cast<Gtk::Button*>(widgets.at(i).get())->signal_clicked().connect(sigc::bind(sigc::mem_fun(*this,&UI_Controller::stop_timer),i ) );
        }

在矢量小部件上,按鈕 start_timer 和 stop_timer 具有不同的值,所以我最終在 start_timer 內部的表達式上創建了 map bind_time,其參數對應於存儲按鈕 start_timer 的矢量小部件上的索引值,但是當我執行 stop_timer 我最終嘗試對實際上對應於小部件向量上的 stop_timer 索引的索引的 Time_Keeper 進行操作,Time_Keeper 不存在,NULL

為了解決 for 循環中的問題,我將一直持續到它到達按鈕所在的 Gtk::Grid,然后我根據它們在網格上的固定位置訪問它們。 關於其他最簡單的方法來獲取按鈕所在的網格的索引並且我知道它有效

我對 C++ 不太熟悉,但我使用了您的代碼並構建了計時器程序來引導它完成啟動和停止操作。 當按下“停止”按鈕時,我也遇到了分段錯誤。 因此,我添加了一些“cout”語句來跟蹤“start_timer”和“stop_timer”函數中的 object 個指針。 我發現在“start_timer”function 中為計時器 object 設置了一個指針引用。但是在執行互補的“stop_timer”function(它是 NULL)時找不到這個指針引用。 以下是啟動和停止執行的終端 output。

Entered timer start
Time keeper timer pointer value: %p0x55dfd78fb390
Entered timer stop
Time keeper timer pointer value: %p0
Segmentation fault (core dumped)

只是為了測試用例,我在“main.cc”程序中立即創建了一個測試計時器object,調用“start_timer”和“stop_timer”。

Time_Keeper *test = new Time_Keeper();
std::cout << "Test time keeper address %p" << test << std::endl;
test->start_timer();
test->stop_timer();

這導致定時器正確關閉而沒有分段錯誤。

Test time keeper address %p0x55dfd7847e50
Entered timer start
Time keeper timer pointer value: %p0x55dfd789e100
Entered timer stop
Time keeper pointer value: %p0x55dfd789e100

我不能肯定地說,但要么需要將啟動計時器 function 和停止計時器 function 同步到同一映射迭代。 作為一個簡單的解決方法,我在“ui-controller.h”文件中添加了一個 static integer 變量,以跟蹤計時器啟動時的迭代引用。

static int poss = 0;

在調用“stop_timer”function 時,索引設置為這個 static integer 而不是順序輸入值。

void stop_timer(int i)
{
    (bind_time[poss]).stop_timer ();
}

然后在“ui-controller.cc”文件中,這個 static 變量在定時器啟動時設置。

    if (bind_time.find(position) == bind_time.end() )
    {
        poss = position;  // Save the timer iteration position.
        bind_time [position] = *(new Time_Keeper());
        (bind_time [position]).start_timer ();
    }

這不是處理這個問題的最優雅的方法,因為我相信可能有更好的方法來保持一致。 但它現在可以完成工作。

希望這不是太雜亂無章,可以讓您朝着正確的方向前進。

問候。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM