【问题标题】:Returning char * instead of string返回 char * 而不是字符串
【发布时间】:2020-10-15 19:05:33
【问题描述】:

如何在 C++11 中更正以下代码:

    const char *what() const noexcept override {
        return "Mtm matrix error: Dimension mismatch: (" + std::to_string(mat1_height) + "," +
               std::to_string(mat1_width)
               + ") (" + std::to_string(mat2_height) + "," + std::to_string(mat2_width) + ")";
    }

如您所见,我返回的是string 而不是const char*,但这不会自动转换吗?以及如何解决?

注意:我想要一些看起来像 c++ 代码的东西,而不是使用 sprintf 的 c 代码

【问题讨论】:

  • "我返回的是字符串而不是字符串" 不,你返回的是 std::string 而不是 const char*
  • @AlgirdasPreidžius 错字,会更正
  • 对此有何提示?
  • 1) “但不会自动转换吗?”不,为什么会这样?它们是 2 种不同的类型。 2) “对此有任何提示吗?”将std::string 存储在您的异常类中,并返回其中的.c_str ()。注意:试图返回在此方法中构造的std::string 中的.c_str (),将调用未定义的行为。
  • 一方面你告诉我调用 .c_str () ,另一方面它会调用未定义的行为。这听起来很矛盾

标签: c++ string class exception char


【解决方案1】:

但这不会自动转换吗?

没有。

以及如何解决这个问题?

将字符串存储为成员,并在what 中调用c_str()。示例:

struct descriptive_name : std::exception {
    std::string msg;

    descriptive_name(
       int mat1_width,
       int mat1_height,
       int mat2_width,
       int mat2_height)
         : msg(
           "Mtm matrix error: Dimension mismatch: ("
           + std::to_string(mat1_height)
           + ","
           + std::to_string(mat1_width)
           + ") ("
           + std::to_string(mat2_height)
           + ","
           + std::to_string(mat2_width)
           + ")"
           )
    {}

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

更好:继承std::runtime_error,不覆盖what,并使用消息字符串初始化基类。示例:

struct descriptive_name : std::runtime_error {
    descriptive_name(
       int mat1_width,
       int mat1_height,
       int mat2_width,
       int mat2_height)
         : std::runtime_error(
           "Mtm matrix error: Dimension mismatch: ("
           + std::to_string(mat1_height)
           + ","
           + std::to_string(mat1_width)
           + ") ("
           + std::to_string(mat2_height)
           + ","
           + std::to_string(mat2_width)
           + ")"
           )
    {}
};

【讨论】:

  • 请阅读 cmets,有人告诉:注意:试图返回在此方法中构造的 std::string 的 .c_str () 会调用未定义的行为。
  • @Daniel 这就是为什么您不应该在该方法中构造字符串的原因。在构造函数中构造它。那就是初始化成员的地方。
  • @Daniel 我添加了示例。
  • 从异常继承和runtime_error有什么区别...
  • 谢谢,最后你能解释一下为什么我之前所做的会导致未定义的行为而这不会吗?
【解决方案2】:

这并不简单,因为您返回的是一个临时对象,您试图将其转换为指针。您可以使用

const char *what() const noexcept override {
        return ("Mtm matrix error: Dimension mismatch: (" + std::to_string(mat1_height) + "," +
               std::to_string(mat1_width)
               + ") (" + std::to_string(mat2_height) + "," + std::to_string(mat2_width) + ")").c_str();
    }

但是转换后对象会被销毁,这将导致实际数据被删除。相反,您可以只复制数据。

const char* what()
{
    std::string temp = "Mtm matrix error: Dimension mismatch: (" + std::to_string(mat1_height) + "," +
                       std::to_string(mat1_width)
                       + ") (" + std::to_string(mat2_height) + "," + std::to_string(mat2_width) + ")";
    char * p = new char[temp.size()+1]{};
    strcpy(p,temp.data());
    return p;
}

请注意,这是低效的,因为您正在创建和销毁对象,并且有一个额外的副本可能会很慢。另外,使用此功能后一定要记得删除char*

【讨论】:

  • 您可以只复制数据。 是的,但现在您可能存在内存泄漏。 (我怀疑调用者不希望返回的值必须被删除。而且,它可能不能被其他overrides 删除。)
  • 最好的情况是你只使用 std::string
  • 请有人提供一个不会泄漏内存或导致问题的解决方案
  • @Daniel the other answer 怎么样? IE。将std::string 存储在异常类本身中。然后在what() const 中返回.c_str() 是安全的,因为异常实例正在充分管理std::string 的生命周期。
猜你喜欢
  • 1970-01-01
  • 2019-09-15
  • 2014-07-28
  • 1970-01-01
  • 2019-01-19
  • 1970-01-01
  • 1970-01-01
  • 2018-11-16
相关资源
最近更新 更多