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

时间:2015-03-14 18:31:54

标签: c++ exception c++11 language-lawyer

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;?

3 个答案:

答案 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,那么必须是参考柜台的一个额外拨款。)