我在 HackerRank 上随意做一些挑战,偶然发现了“继承代码”,我试图用这个来解决:
class BadLengthException : public exception {
private:
const char* message;
public:
BadLengthException(int n_) {
this->message = to_string(n_).c_str();
}
const char * what() const throw() {
return this->message;
}
};
由于它不起作用(输出为空),我已经搜索了原因,并且我发现了这个关于同一问题的问题。我想我确实理解所提出的解决方案,但我仍然对我的尝试感到非常困惑:
我知道该字符串to_string(n_).c_str()
可以被视为局部变量,就像上述问题中的示例一样,但为什么在what()
调用时它仍然被视为局部变量?难道它不应该通过初始化保留下来message
,从而在调用时可用吗what()
?
const char*
是一个指向原始 C 字符串的指针。std::string
它不是拥有该字符串并管理包含该字符串的缓冲区的分配/释放的容器对象(如)。to_string(int)
返回std::string
带有数字字符串表示形式的 a。然后c_str()
返回指向该字符串的指针。但在 中
this->message = to_string(n_).c_str();
,首先std::string
构造一个临时对象,然后message
将其设置为指向该字符串的指针。但之后,临时对象std::string
被删除(这会释放其缓冲区),并且message
现在是一个悬空指针,指向不再分配的内存。一种解决方案是制作
this->message
一个std::string
. 并作出what()
回报this->message.c_str()
。to_string(n_)
是暂时的。它在表达式结束时过期。c_str()
在存活的短时间内获取指向临时字符串数据缓冲区的指针string
,并且存储该指针,几乎立即给程序留下一个悬空指针。string
恐怕你被困住了。一个潜在的解决方案:
注意:在异常中分配存储是有风险的,如果无法分配该存储并且最终会抛出异常,那么事情会变得非常糟糕,但是您可以使用预先分配的数组来缓解这种情况,并避免
std::string
通过 go old school withsprintf
或类似的方式使用。message
是一个悬空指针。std::string
返回的临时值std::to_string
在完整表达式的末尾被销毁。您需要将消息存储在某处。最好的地方很可能是在
std::string
.例子:
请注意,这
const throw()
是 C++11 之前的版本。从 C++11 开始,它应该是const noexcept override
.一个更简单的选择是继承
std::runtime_error
,这就是人们在创建自定义异常时通常这样做的原因。它提供存储以及what()
覆盖,因此您所要做的就是: