C++ 11引入了使用`const char*`的异常构造函数.但为什么?

Lig*_*ica 30 c++ exception language-lawyer c++11

标准库缺陷#254,它涵盖了新的异常构造函数的添加:

std::logic_error::logic_error(const char* what_arg);
std::runtime_error::runtime_error(const char* what_arg);
// etc.
Run Code Online (Sandbox Code Playgroud)

作为基本原理,存储std::strings打开了一些与可能存在问题的内存分配有关的蠕虫.

然而,在休息室中orlp开始讨论之后,我觉得除非标准要求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!
   }
}
Run Code Online (Sandbox Code Playgroud)

但我看不到任何这样的任务.事实上,异常对象是否深层复制what_arg似乎完全没有指定.

如果他们这样做,那么首先添加重载(消除额外分配)的大部分理由似乎完全是空的.

这可能是标准缺陷,还是我在这里遗漏了什么?
这只是"程序员:不要在任何地方传递悬空指针"的情况吗?

Jer*_*fin 19

这允许(或者至少显然是为了方便 - 在下面看到更多)实现,以消除副本,如果它可以检测到(通过本身不是标准化的方式)传递的是字符串文字或静态的其他内容储存期限.

例如,假设编译器将所有字符串文字汇集到一个由__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);
}
Run Code Online (Sandbox Code Playgroud)

链接DR中的最终评论指出:

[Oxford:提议的解决方案只是解决了使用const char*和字符串文字构造异常对象的问题,而无需显式包含或构造std :: string.]

因此,根据当时的评论,委员会意识到这些超载并未满足所有需求,但确实解决了(至少被认为是)需求.

(几乎)确实如果实施可以提供这些超载,即使它们没有被标准规定 - 尽管如此,委员会似乎已经确信添加它们对于上述情况主要(如果不是唯一的话)是有用的 - - 当字符串文字传递给ctor时,只有一个浅拷贝.

  • @LightnessRacesinOrbit然后我会说-1和unaccept,因为这并不能解释为什么要添加这个. (6认同)