26

我有字符串常量,用于在我的应用程序的多个位置使用的字符串:

namespace Common{
    static const std::string mystring = "IamAwesum";
}

当发布有关其他内容的问题时(编译期间未包含在目标中的 .h 文件会发生什么情况?),另一位用户发表了以下评论:

请注意,在这种情况下,您的静态字符串是全局的。所以他们可以随时创建异常并且不能被捕获。我建议您使用返回字符串引用的函数。std::string const &mystring { 静态 std::string const mystring = "IamAwesum"; return mystring} 通过这种方式,您的对象仅在需要时才构造

有人可以解释为什么以我上面这样做的方式使用静态 const 字符串会引发异常吗?

4

3 回答 3

33

N4140 § 3.6.2 [basic.start.init]/4

具有静态存储持续时间的非局部变量的动态初始化是否在main.

​</p>

N4140 § N4140 15.3 [除了.handle]/ 13

具有静态存储持续时间的对象的析构函数或具有静态存储持续时间的命名空间范围对象的构造函数中引发的异常不会被function-try-block on捕获main()

您根本无法捕获由字符串的构造函数生成的异常,例如std::bad_alloc.

(观点)话虽如此,对于这么小的字符串,我觉得这种考虑是偏执的。

于 2016-11-02T10:28:06.537 回答
5

唯一的“问题”——如果你可以这样称呼它——我在你的代码中看到的是,你将已经是常量的数据不必要地复制到动态分配的缓冲区中是浪费的(这在形式上是常量,但实际上不是)。这将使用两倍于必要的物理内存并进行不必要的复制。

有关系吗?几乎可以肯定,没有。即使在“相当有限的内存”系统上,现在也很难注意到这一点,无论是从执行时间的角度来看,还是从它的内存消耗来看。

至于异常,当然从技术上讲std::string,必须进行的分配可能会失败,因此构造函数可能会抛出,而您将无法捕获它。但请现实一点。
这几乎可以保证不会发生,但即使它确实发生了......如果在程序启动时为几个字符串分配内存这样微不足道的事情失败了,那么您将遇到一个完全不同规模的非常非常严重的问题!
此外,正如在上面对另一个答案的评论中指出的那样:假设确实发生了这种情况,您将如何处理?该程序完全无法运行,因此您可以想象杀死该程序并没有太多的余地。

现在,随着 C++17 离我们不远并且string_view已经std::experimental在几个主流编译器中可用,您可以尝试另一件事:使用正确的东西

string_view与 a 相反,Astring不会分配非常量内存,将常量数据复制到其中,然后假装它是常量。相反,它将直接管理指向常量数据的指针,仅此而已。
这样,您的常量是真正的(不仅仅是形式上的)常量,没有分配,没有异常的可能性,也没有双重内存使用。在大多数情况下,它的外观和气味仍然像string. 唯一显着的区别是 astring_view不保证 nul 终止(但它指向的字符常量确实如此,所以这无关紧要),以及它确实是常量,不可修改的事实......这正是你想要的。

于 2016-11-02T13:59:41.033 回答
4

pdf 文档主要是指来自对象 ctor 的异常和使用静态或动态链接库的初始化顺序惨败。

我在您的异常代码中看到的唯一危险是 std::string 的 ctor 在被调用时是否会抛出。

如果您真的想安全起见,可以使用 static const char* mystring 代替,它不会调用 C++ ctor。

还有代码在共享库中的问题,然后需要将其放置在进程的地址空间中。如果您不使用复杂的ctors(可以抛出的ctors),我认为这不是一个主要问题。

于 2016-11-02T10:37:31.380 回答