错误时停止代码执行(C ++)

时间:2014-05-04 04:50:01

标签: c++ qt qwidget qtgui qmainwindow

我有一个用C ++编写的库。该库有一个函数,它接受命令作为字符串并执行它们。如果遇到错误(在命令中或在运行命令时),将调用“错误函数”,它会执行一些清理并最终调用exit(1)。我现在正在尝试使用图形用户界面(使用Qt)来实现库。问题是当遇到错误时,调用exit并且我的应用程序崩溃。我可以访问库源代码,但我想继续修改源代码。

我正在考虑重写错误函数,使它只是停止执行代码并保持空闲状态,直到另一个命令从用户界面传递给库。问题是我不知道如何去做。我基本上寻找一个等效于退出系统调用的函数调用(以便错误函数永远不会返回到生成错误的代码),除了我不希望应用程序退出但只是转到空闲状态并等待来自用户界面的调用。

如果有其他方法可以实现这一点,请告诉我。如果您需要更多详细信息,请与我们联系。

提前致谢,

以下是一些显示我的问题的代码

#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;

void error_func(string error); 
void create_sphere(float radius); 
void create_rect(float length, float width); 

int main()
{
  string command; 
  while(1)  {
    cout << "Enter command: "; 
    cin >> command; 

    if(command.compare("create_sphere") == 0)  {
      float radius; 
      cout << "Enter radius: "; 
      cin >> radius;
      create_sphere(radius); 
    }
    else if(command.compare("create_rect") == 0)  {
      float l, w; 
      cout << "Enter length and width: "; 
      cin >> l >> w; 
      create_rect(l, w); 
    }
    else if(command.compare("quit") == 0)
      break; 
  } 
}

void create_sphere(float  radius)
{
  if(radius < 0)
    error_func(string("Radius must be positive")); 

  cout << "Created sphere" << endl; 
}

void create_rect(float length, float width)
{
  if(length < 0)
    error_func(string("Length must be positive")); 

  if(width < 0)
    error_func(string("Width must be positive")); 

  cout << "Created rectangle" << endl;
} 

void error_func(string error)
{
  // do some cleanup
  cout << "ERROR: " << error << endl; 
  exit(1); 
}

假设图书馆提供了create_spherecreate_recterror_func。我可以根据需要修改error_func但不修改其他函数(因为有很多这样的函数)。

现在遇到错误时,我想回到main中的while循环,以便我可以继续接受其他命令。

3 个答案:

答案 0 :(得分:1)

  

我基本上在寻找一个等同于退出系统调用的函数调用(这样错误函数永远不会返回到生成错误的代码),除了我不希望应用程序退出但只是转到空闲状态等待来自用户界面的电话。

基本上,您正在寻找一个事件循环。典型的最小Qt程序如下:

#include <QApplication>
#include <QMainWindow>

int main(int argc, char **argv)
{
    QApplication(argc, argv);
    QMainWindow w;
    w.show();
    return application.exec(); // What you want instead of exit
}

现在,您可以用自己的类替换QMainWindow,并在尝试从用户界面处理命令时声明一个调用的插槽。

#include <QWidget>

...

class MyWidget : public QWidget
{
    Q_OBJECT
    public:
        explicit MyWidget(QWidget *parent) : QWidget(parent)
        {
            connect(sender, SIGNAL(mySignal()), SLOT(handleCommand()));
        }
    public slots:
        void handleCommand()
        {
            // Handle your command here.
            // Print the error code.
            qDebug() << error_func(string("Radius must be positive"));
            // or simply:
            qDebug() << "Radius must be positive";
        } // Leaving the scope, and getting back to the event loop
}

对于伪库,如果它退出,它确实如此。没有fixint库,你没有太多可以做的事情。这是大多数图书馆的非常糟糕的行为。

修改不是退出,而是返回错误代码 - 这是Qt软件中的一般做法 - 如果他们愿意,可以在申请时退出。

在您的情况下,申请不会退出。同样,库函数退出是一个非常糟糕的主意。甚至Qt也没有做到,除了几百万LOC的1-2次。

我建议抛出异常。它在Qt软件中通常不常见,只需使用Qt的其余部分就可以使用错误代码,使您的软件保持一致。

答案 1 :(得分:0)

创建错误状态(空闲状态)并使该功能永不失败。错误状态应该变得可见并且可以通过某种方式解决。

如果无法达到可解析的错误状态,则可能会回滚到某个先前(初始)状态。

如果无法使用上述选项,则会出现严重故障(软件,硬件,数据),您可能会终止该程序。

以上所有都可以通过返回值或getter函数(指示当前状态)和设置器操作当前状态来实现 - 退出调用是库中的一个糟糕的解决方案。如果您具有无法解析的状态或无法回滚到先前状态,则可能会抛出异常,在用户界面中捕获它并在显示问题后终止该程序。

答案 2 :(得分:0)

您应该安装一个消息处理程序,它将自动减少您的大部分工作。 此外,它还有助于减少调试。这是我的Qt5应用程序的消息处理程序。如果您使用的是Qt4,则需要稍微调整一下:

QFile *logFile = NULL;//The file in which you will output the debug info to
QTextStream *logStream = NULL;//text stream for your log file
QMutex *mutex = NULL;//Always use mutex if you are multi threading your application
bool *debugMode = NULL;//it just a flag in case you want to turn off debugging
bool errorMsg = false;//use the value of this variable after QApplication::exec() if you need to show an error message

void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
 {
    if(((logFile != NULL) && (debugMode != NULL)))
    {
        mutex->lock();
         switch (type)
         {
         case QtDebugMsg:
             if(!*debugMode)
             {
                 mutex->unlock();
                 return;
             }
             *logStream << msg;
             logStream->flush();
             break;
         case QtWarningMsg:
             if(!((QString)context.function).contains("setGeometry"))
             {
                 *logStream << "\n*** Warning ***\n";
                 *logStream << msg << endl;
                 *logStream << "Category: " << context.category << endl;
                 *logStream << "File: " << context.file << endl;
                 *logStream << "Function: " << context.function << endl;
                 *logStream << "Line: " << context.line << endl;
                 *logStream << "Version: " << context.version;
                 *logStream << "\n*** Warning Complete ***\n";
                 logStream->flush();
                 errorMsg = true;
                 SessionManager::get_obj()->saveCurrentSession();
             }
             break;
         case QtCriticalMsg:
             *logStream << "\n*** Critical ***\n";
             *logStream << msg << endl;
             *logStream << "Category: " << context.category << endl;
             *logStream << "File: " << context.file << endl;
             *logStream << "Function: " << context.function << endl;
             *logStream << "Line: " << context.line << endl;
             *logStream << "Version: " << context.version;
             *logStream << "\n*** Critical Complete ***\n";
             logStream->flush();
             errorMsg = true;
             SessionManager::get_obj()->saveCurrentSession();
             break;
         case QtFatalMsg:
             *logStream << "\n*** Fatal ***\n";
             *logStream << msg << endl;
             *logStream << "Category: " << context.category << endl;
             *logStream << "File: " << context.file << endl;
             *logStream << "Function: " << context.function << endl;
             *logStream << "Line: " << context.line << endl;
             *logStream << "Version: " << context.version;
             *logStream << "\n*** Fatal Complete ***\n";
             logStream->flush();
             errorMsg = false;
             SessionManager::get_obj()->saveCurrentSession();
             ShowErrorMsg(SessionManager::getSessionName());
             exit(0);
         }
         mutex->unlock();
    }
 }

要安装消息处理程序,请在GUI的main()中添加以下代码。

qInstallMessageHandler(myMessageOutput);

如果您愿意,可以忽略对setGeometry的检查,但我发现不必要地发出此警告。所以你可以保留它。 此外,您可能希望有一个会话管理器,它会在遇到错误时自动保存当前会话。

完成此操作后,您可以在要终止申请时安全地拨打qFatal(),或者如果您想要其他功能,请使用qCritical()