标准库缺陷#254,其中包括添加新的异常构造函数:
std::logic_error::logic_error(const char* what_arg);
std::runtime_error::runtime_error(const char* what_arg);
// etc.
给出了一个基本原理,即存储std::string
s会打开一些与潜在的内存分配问题有关的蠕虫病毒。
但是,在休息室中的orlp发起讨论之后,令我惊讶的是,除非该标准要求what_arg
仅使用字符串文字(或指向静态存储持续时间的其他缓冲区的指针),否则它必须执行C字符串的副本,以保持成员函数的良好定义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
似乎是完全不确定的。
如果它们这样做了,那么在第一位添加重载(消除其他分配)的大部分理由似乎完全是虚无。
这是潜在的标准缺陷,还是我在这里遗漏了一些东西?
这只是“程序员:不要在任何地方传递悬空指针”的情况吗?
这允许(或至少显然旨在促进-参见下文中的更多内容)实现在可以检测到(通过自身未标准化的方式)传递的内容是字符串文字或其他带有静态内容的情况下消除副本储存期限。
举例来说,假设编译器将所有字符串文字集中在一起,__string_literals_begin
并以和分隔范围__string_literals_end
。然后在构造函数内部的某处std::exception
可能具有以下一般顺序的代码:
namespace std {
exception::exception(char const *s) {
if (in_range(s, __string_literals_begin, __string_literals_end)) {
stored_what = s;
destroy_stored_what = false;
}
else {
stored_what = dupe(s);
destroy_stored_what = true;
}
// ...
}
exception::~exception() {
if (destroy_stored_what)
delete_string(stored_what);
}
链接的DR中的最后评论指出:
[牛津:提出的解决方案只是解决了用const char *和字符串文字构造异常对象的问题,而无需显式包含或构造std :: string。]
因此,基于当时的评论,委员会意识到这些过载并不能满足所有需求,但确实满足了(至少被认为是)需求。
(几乎)可以肯定的是,即使没有标准的强制要求,实现也可以提供这些重载。尽管如此,委员会似乎已经确信添加它们是有用的,主要是(如果不是专门的话)用于上述情况- -将字符串文字传递给ctor时,仅执行浅表复制。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句