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

Posted

技术标签:

【中文标题】出错时停止代码执行 (C++)【英文标题】:Stop code execution on error (C++) 【发布时间】:2014-05-04 04:50:01 【问题描述】:

我有一个用 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 循环,以便我可以继续接受其他命令。

【问题讨论】:

请出示代码! 也许你可能会throw 一些异常而不是 ̀ exit`-ing ? @LaszloPapp,我提供了一个示例代码。 听起来您正在寻找一个带有自己事件循环的模态消息框。大多数 UI 框架都提供了诸如库函数之类的功能。要返回主应用程序,绕过导致错误的代码,您可以抛出异常。 @BenVoigt:什么?! OP在哪里提到“消息框”?此外,一般来说,抛出异常......在这种情况下,在 qt 软件项目中是个坏主意。 【参考方案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

至于虚假库,好吧,如果它退出,它就会退出。如果没有修复库,您将无能为力。从大多数图书馆来看,这是一种非常糟糕的行为。

修改不会退出,而是返回一个错误代码 - 这是 Qt 软件中的一般做法 - 并将其留给应用程序,如果他们愿意,何时退出。

在您的情况下,应用程序不会退出。同样,退出库函数是一个非常糟糕的主意。甚至 Qt 也只能在几百万 LOC 中执行 1-2 次。

我建议不要抛出异常。这在 Qt 软件中通常不常见,您可以像 Qt 的其余部分一样使用错误代码来使您的软件保持一致。

【讨论】:

我的 Qt 代码中实际上有类似的东西。但是,函数 handleCommand() 最终会调用库函数,如果该库函数调用 exit(1),我的应用程序也会退出。如果库函数遇到错误,我想重新进入主事件循环。 @rkumar310:如果它退出,它会退出。修改不是退出,而是返回一个错误代码,并在退出时将其留给应用程序。退出库函数是一个非常糟糕的主意。甚至 Qt 也只能在几百万 LOC 中执行 1-2 次。见最后答案更新。 我当然需要帮助,否则我不会在这里。原始代码很大并且跨越多个文件,我不确定发布整个代码(如果可能的话)会有所帮助。基于 std 的示例基本上以更简单的设置显示了我的问题。我想修改error_func,以便当它被调用时,它只是回到main 中的while 循环,绕过发生错误的函数中的所有后续代码。很抱歉,如果它造成任何混乱。当然,具体情况取决于我使用的是 Qt 而不是控制台应用程序这一事实。 我同意你的观点,退出库函数是一个非常糟糕的主意,但不幸的是,库就是这样编写的。我只是想弄清楚是否有任何解决方法。 @rkumar310:正如我已经写过的,修改库以返回错误代码或不调用库。这两个都在我的答案的 sn-p 中用两个不同的 QDebug 语句进行了演示。【参考方案2】:

发明一个错误状态(空闲状态)并使函数永远不会失败。错误状态应该变得可见并且可以通过某种方式解决。

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

如果上述选项不可行,则表示您遇到了严重故障(软件、硬件、数据),您可能会终止程序。

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

【讨论】:

存在调用 -> 退出 :)【参考方案3】:

您应该安装一个消息处理程序,它会自动减少您的大量工作。 此外,它也有助于减少调试。这是我的 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()

【讨论】:

以上是关于出错时停止代码执行 (C++)的主要内容,如果未能解决你的问题,请参考以下文章

代码块停止使用 gnome-terminal (linux) 执行

我必须编写一个基本上在 c++ 中执行 strlen() 函数的代码,我哪里出错了?

求助:为啥我编的C++程序在自己电脑上能正常运行,但编译后挂在后台linux系统下就总是运行一半后出错,

在 Qt 中将 x 可执行文件作为按钮事件运行时出错

将新工作表添加到XLSM宏Excel文件时出错

尝试在 Windows 上执行 C++ 时出错(通过 MinGW 编译)