自定义派生的std :: exception类的“ what”函数返回晦涩的废话

时间:2018-08-04 15:28:22

标签: c++ qt inheritance exception std

我有一个自std::exception派生的自定义异常类:

CameraControlException.h

#ifndef CAMERACONTROLEXCEPTION_H
#define CAMERACONTROLEXCEPTION_H

#include <QString>
#include <exception>
#include "ProxOnyx/ProxOnyxUsb1_3M.h"

class CameraControlException : public std::exception
{
    public:
        explicit CameraControlException(QString statusText, int errorNumber);
        virtual const char *what() const noexcept;

    private:
        QString errorMessage;
        int errorNumber;
};

#endif // CAMERACONTROLEXCEPTION_H

CameraControlException.cpp

#include "CameraControlException.h"
#include <iostream>

CameraControlException::CameraControlException(QString statusText, int errorNumber) :
    errorMessage(QString("Status: ").append(statusText)),
    errorNumber(errorNumber)
{
    this->errorMessage.append("\nSome text in new line");
}

const char *CameraControlException::what() const noexcept {
    // Output the message like return them:
        std::cout << "this->errorMessage.toLatin1().data(): " << std::endl;
        std::cout << this->errorMessage.toLatin1().data() << std::endl; 
            // Works well but function is called twice?!
            // Output:
                // Status: this is an exception test
                // some text 

    return this->errorMessage.toLatin1().data(); // Return the message as 'const char *'
}

我有一个名为QMainView的{​​{1}},它在自定义异常处理函数中处理异常。此函数捕获任何RaGaCCMainView并调用std::exception来检索错误消息。现在,当我真正做到这一点时,我就变得毫无意义。这是异常处理函数:

what

我通过在传递包含函数特定逻辑的lambda的任何其他函数中调用它来使用此异常处理程序。对于这个问题,我使用了名为template <typename TaskFunction, typename ExceptionFunction> void RaGaCCMainView::functionCallerExceptionHandler( TaskFunction &&taskFunction, ExceptionFunction &&exceptionFunction ) { try { taskFunction(); } catch (std::exception& exception) { // Here i catch any exception std::cout << "exception.what(): " << std::endl; std::cout << exception.what() << std::endl; // Calling what here just gives some cryptic nonsense: // ÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝ // NOTE: I get the output inside the 'what' function twice! exceptionFunction(); } } 的{​​{1}}的 on_clicked 函数:

QPushButton

实际上,我不知道问题出在哪里。我只是检索对现有异常的引用,该异常调用它已被调用一次的现有what函数被调用,但是由于某种原因执行了两次。

我只想检索在调用someButton函数时正确返回的void RaGaCCMainView::on_testButton_clicked() { this->functionCallerExceptionHandler([]{ throw CameraControlException(QString("this is an exception test"), 1); }, []{}); } s CameraControlException中存储的错误消息...

有人可以启发我解决问题所在吗?

2 个答案:

答案 0 :(得分:6)

QString::toLatin1返回一个临时QByteArray。在CameraControlException::what返回之前,它会被销毁,留下一个悬空的指针。

最简单的解决方法是将QString::toLatin1的结果存储为类成员变量,从而使对CameraControlException::what的调用不再有效。

答案 1 :(得分:2)

其他答案描述了该问题。由于您真正关心的是what,而不是QString,因此只需存储QByteArray(或等效值)而不是QStringQByteArraystd::string具有相似的界面,因此可以轻松地修改代码以使用其中任何一个。

其他说明:当采用非算术或指针类型的输入时,请通过const引用传递它们。数据成员是不可变的,应声明为const。这是一个很小的类,因此使其仅保留标题是很有意义的。当跨多个文件的文件很少时,遵循这样的代码变得不必要。特别是-不要在问题中逐字张贴此类代码。首先将其最小化。

我还演示了如何处理在消息中添加错误号的问题。

class CameraControlException : public std::exception {
    public:
        explicit CameraControlException(const QString &status, int errNo) :
           CameraControlException(status.toUtf8(), errNo) {}
        explicit CameraControlException(const QByteArray &status, int errNo) :
           errorMessage(makeMessage(status.data(), errNo)),
           errorNumber(errNo) {}
        explicit CameraControlException(const std::string &status, int errNo) :
           errorMessage(makeMessage(status.data(), errNo)),
           errorNumber(errNo) {}
        explicit CameraControlException(const char *status, int errNo) :
           errorMessage(makeMessage(status, errNo)),
           errorNumber(errNo) {}
        virtual const char *what() const noexcept override {
           return errorMessage.data();
        }

    private:
        using MsgType = std::conditional_t<false, std::string, QByteArray>;
        MsgType const errorMessage;
        int const errorNumber;
        static MsgType makeMessage(const char *status, int errNo) {
           MsgType message;
           message.reserve(128); // typical message size
           message.append("Status (#");
           message.append(QByteArray::number(errNo).constData());
           message.append("): ");
           message.append(status);
           message.append("\nSome text in new line");
           return message;
        }             
};

您还可以使用makeMessage以安全的方式实现snprintf

status MsgType makeMessage(const char *status, int errNo) {
  MsgType message;
  static const char fmt[] = "Status (#%d): %s\nSome text in new line";
  auto n = snprintf(nullptr, 0, fmt, errNo, status);
  assert(n >= 0);
  message.resize(n);
  n = snprintf(message.data(), message.size(), fmt, errNo, status);
  assert(n == message.size());
  return message;
}