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

轨道轻赛

标准库缺陷#254,其中包括添加新的异常构造函数:

std::logic_error::logic_error(const char* what_arg);
std::runtime_error::runtime_error(const char* what_arg);
// etc.

给出了一个基本原理,即存储std::strings会打开一些与潜在的内存分配问题有关的蠕虫病毒。

但是,在休息室中的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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么C ++ 11引入了委托构造函数?

具有char *构造函数的异常类

C API:为什么函数使用带有缓冲区+大小的returnParameters而不是返回char *

为什么在 c++11 中调用了复制构造函数而不是移动构造函数?

为什么在C ++中使用私有副本构造函数与已删除副本构造函数

为什么带有虚函数的C ++类必须具有非平凡的复制构造函数?

在C ++中,为什么要在`const char array`上重载一个函数,并包装一个`const char *`的私有结构?

从C ++的构造函数中向成员const char *变量分配字符串文字时会发生什么?

为什么C不允许从char **到const char * const *的隐式转换(而C ++允许)?

C ++为什么const LPSTR与const char *不同?

C ++-为什么在没有明显的构造函数匹配时为什么会编译此代码?

C ++ 11:带有std :: move()的'decltype类实例声明'不调用'move构造函数'。为什么?

C从函数返回const char指针或char指针

C函数原型:\\ char * strinv(const char * s);

为什么在构造函数初始化程序中初始化 const char 数组成员不兼容?

为什么返回带有字符串文字的const char *的函数起作用?

C ++:没有匹配的调用函数:为什么需要一个空的构造函数?

C ++ 11引入了标准化的内存模型。这是什么意思?它将如何影响C ++编程?

错误C2512:没有合适的默认构造函数-为什么在构造函数中初始化属性?

为什么C ++ 11从std :: vector的fill构造函数原型中删除默认值?

具有char **参数的C ++函数

C ++:使用委托构造函数时选择`const char *`vs`std :: string`

使用Android NDK在constexpr构造函数(c ++ 17)中分配给const char *失败

为什么闭包类型/ lambdas在C ++中没有默认构造函数

C ++-为什么可以直接在Copy构造函数中访问传递的对象的私有变量?

为什么C#中的通用参数没有构造函数与参数的约束?

C ++-为什么默认构造函数即使在私有继承中也可以工作

为什么我的C#基本构造函数没有被调用?

C++ char a[20] = {0} 和 char *a= new char[20]() 有什么区别