0

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

#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() 当前不会返回任何内容,因为没有分配成员变量。我把它省略了,因为我从 strcat() 调用中得到了分段错误。

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

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

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

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

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;
  }
4

2 回答 2

1

strcat正如 Silvio 在另一条评论中提到的,如果缓冲区不能包含结果字符串,则不能使用。在这种情况下,您还有一个问题,即您将 a 传递const char *strcat它是一个 no no(文字字符串是 const)。

我建议您将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;
};
于 2022-01-22T20:05:05.053 回答
0

来自cppreference

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

...

如果目标数组对于 src 和 dest 的内容以及终止空字符都不够大,则行为未定义。

因此,如果您调用这个构造函数时使用的 achar*恰好足以存储原始字符串,然后您尝试在其上附加更多内容,您会得到未定义的行为。不要调用strcat不知道大小的缓冲区。您的第二个解决方案,您预先分配 100 个字符(假设这对您的用例来说足够了),然后使用缓冲区是正确的。一个完全通用的解决方案将调用strlen两次并分配一个足够大的缓冲区以容纳两个字符串,但如果这只是一个简单的示例,这可能超出范围。

于 2022-01-22T16:11:21.197 回答