Standard library defect #254,它涵盖了新的异常构造函数的添加:
std::logic_error::logic_error(const char* what_arg);
std::runtime_error::runtime_error(const char* what_arg);
// etc.
理所当然地认为存储std::string
s会打开一些与可能存在问题的内存分配有关的蠕虫。
然而,following initiation of a discussion by orlp in the Lounge,除非标准要求what_arg
只是一个字符串文字(或指向静态存储持续时间的其他缓冲区的指针),否则它会让我感到震惊无论如何要执行C-string的副本,以保持成员函数what()
的明确定义。
那是因为:
void bar() {
char buf[] = "lol";
throw std::runtime_error(buf);
}
void foo() {
try {
bar();
}
catch (std::exception& e) {
std::cout << e.what() << '\n'; // e.what() points to destroyed data!
}
}
但是我看不出任何这样的任务。实际上,是否完全未指定异常对象深层复制what_arg
。
如果他们做,那么首先添加重载(消除额外分配)的大部分理由似乎完全是空的。
这可能是标准缺陷,还是我在这里遗漏了什么? 这只是&#34;程序员的情况:不要在任何地方传递悬空指针&#34;?
答案 0 :(得分:4)
我不确定这是不是原因,但有一点是runtime_error保证它的复制构造函数不会抛出,这表明某种引用计数机制。
额外的构造函数意味着它只需要制作一个副本,从char *到底层mechinsm,而不是两次。一旦进入一个字符串然后进入参考机制
答案 1 :(得分:3)
缺陷的解决方案解决了另一个问题。缺陷的底部有这个注释:
[牛津:提议的解决方案只是解决了使用const char *和字符串文字构造异常对象的问题,而无需显式包含或构造std :: string。 ]
答案 2 :(得分:2)
libc ++如何处理这个问题?
他们目前使用引用计数字符串来存储消息:
class _LIBCPP_EXCEPTION_ABI logic_error
: public exception
{
private:
_VSTD::__libcpp_refstring __imp_;
__imp_
的初始化位置如下:
logic_error::logic_error(const string& msg) : __imp_(msg.c_str()) {}
logic_error::logic_error(const char* msg) : __imp_(msg) {}
此字符串__libcpp_refstring
在存储新char const*
时确实会分配一个新缓冲区:
explicit __libcpp_refstring(const char* msg) {
std::size_t len = strlen(msg);
_Rep_base* rep =
static_cast<_Rep_base *>(::operator new(sizeof(*rep) + len + 1));
但是,当然,__libcpp_refstring
的拷贝构造函数不会分配新的缓冲区。
(是的,这并没有回答这个问题,但它应该对我认为的问题有所了解。例如,如果std::string const&
中只有logic_error
ctor,那么必须是参考柜台的一个额外拨款。)