自定义异常 class,使用基数 class,带有多个参数

custom exception class, using a base class, with multiple arguments

所以我正在为我正在编写的程序设置自定义异常 classes。我正在创建一个包罗万象的基础 class,我将主要将其用作通用异常。这个基础 class 将被其他几个自定义异常继承。这是基础 class 和一个额外的例外 classes,将有 10 多个子 classes 从父 class.

继承
#include <exception>
#include <string>
#include <string.h>

class AgentException : public std::exception
{

protected:
  char *msg;

public:
  AgentException() : msg("AgentException"){};
  AgentException(char *m) : msg(m){};
  AgentException(char *m, std::string d)
  {

    strcat(m, d.c_str()); //aware this fails. its a segmentation fault
  };
  ~AgentException() = default;

  const char *what() const throw()
  {

    return (const char *)msg;
  }
};

class ConnectionFailed : public AgentException
{

private:
  std::string eType = "ConnectionFailed";

public:
  ConnectionFailed() : AgentException("ConnectionFailed"){};
  ConnectionFailed(std::string d) : AgentException("ConnectionFailed: ", d){};
  ~ConnectionFailed() = default;
};

我知道上面的代码 what() 当前不会 return 任何东西,因为没有分配成员变量。我忽略了它,因为我从 strcat() 调用中遇到了分段错误。

我已经为父 class 创建了多个构造函数,因为有时我想要传递默认值、单个值,甚至两个参数。对于子 class,它总是至少将 class ID 传递给父,在某些情况下,我可能需要将字符串变量与 class 一起传递ID。字符串变量 std::string 是必须的。这些是我要使用的指令。

最初我在 classes 中将所有消息变量设置为 std::string,但我最终 运行 遇到了与以下相关的问题what() 函数。我不知道如何将 std::string 转换为 return 作为 const char*。在做了一些研究之后,我发现在异常 class 中使用字符串是一个坏主意,因为它会捕获任何可能在

中发生的异常

所以我将所有内容都转换回 const char*,但现在我似乎无法从 what()。这些问题都源于我无法弄清楚不同类型的串联。

通过对 AgentException class 的更改,我可以得到一些可以正常工作的东西 class。

protected:
  char msg[100];

public:
  // AgentException() : msg("AgentException"){};
  // AgentException(char *m) : msg(m){};
  AgentException(const char *m, std::string d)
  {

    strcpy(msg, m);
    strcat(msg, d.c_str());
    
  };

我可以使此更改在整体上起作用,但感觉这不是正确的方法。有人可以向我提供一些关于他们将对此设置进行的更改的见解吗?

我目前正在通过抛出 AgentException 或 ConnectionFailed 异常并捕获 Base AgentException 来进行测试。我一直在轮换,看看有没有什么不同的反应。

try
  {
    throw ConnectionFailed("test");
  }
  catch (const AgentException &e)
  {

    std::cout << "----------------" << std::endl;
    std::cerr << e.what() << '\n';
    std::cout << "_________________" << std::endl;
  }

来自cppreference

char *strcat( char *dest, const char *src );

...

The behavior is undefined if the destination array is not large enough for the contents of both src and dest and the terminating null character.

因此,如果您使用刚好足以存储 原始 字符串的 char* 调用此构造函数,然后尝试向其追加更多内容,您会得到未定义的行为。不要在不知道大小的缓冲区上调用 strcat。你的第二个解决方案,你 pre-allocate 100 个字符(假设这对你的 use-case 来说足够了)然后使用 that 缓冲区是正确的。一个完全通用的解决方案将调用 strlen 两次并分配一个足够大的缓冲区来容纳两个字符串,但如果这只是一个简单的示例,则可能是 out-of-scope。

正如 Silvio 在另一条评论中提到的,如果缓冲区不能包含结果字符串,则不能使用 strcat。在这种情况下,您还会遇到将 const char * 传递给 strcat 的问题,这是不可以的(文字字符串是常量)。

我建议您将 msg 变量更改为 std::string。然后它将能够增长以容纳连接的消息,并为您管理内存。

class AgentException : public std::exception
{

protected:
  std::string msg;

public:
  AgentException() : msg("AgentException") {};
  AgentException(const char *m) : msg(m){};
  AgentException(const char *m, const std::string& d)
  {
      msg = m + d;
  };
  ~AgentException() = default;

  const char *what() const throw()
  {
      return msg.c_str();
  }
};

class ConnectionFailed : public AgentException
{
public:
  ConnectionFailed() : AgentException("ConnectionFailed"){};
  ConnectionFailed(const std::string& d) : AgentException("ConnectionFailed: ", d){};
  ~ConnectionFailed() = default;
};