我有字符串常量,用于我在app中多个位置使用的字符串:
namespace Common{
static const std::string mystring = "IamAwesum";
}
在发布有关其他内容的问题(What happens to a .h file that is not included in a target during compilation?)时,另一位用户发表了以下评论:
请注意,在这种情况下,您的静态字符串是全局的。他们是 可以在任何时候创建一个例外,并且无法捕获。我劝告你 使用返回字符串引用的函数。的std :: string const& mystring {static std :: string const mystring =" IamAwesum&#34 ;; 通过这种方式返回mystring}你的对象只在需要时构造
有人可以解释为什么以我上面这样做的方式使用静态const字符串,冒着抛出异常的风险吗?
答案 0 :(得分:31)
N4140§3.6.2[basic.start.init] / 4
它是实现定义的动态初始化 具有静态存储持续时间的非局部变量在之前完成
main
的第一个陈述。
N4140§N414015.3 [except.handle] / 13
在具有静态存储的对象的析构函数中抛出异常 持久性或具有静态的命名空间范围对象的构造函数
main()
上的 function-try-block 未捕获存储持续时间。
你根本无法捕获字符串构造函数生成的异常 - 比如std::bad_alloc
。
(意见)话虽如此,对于这么小的字符串,我觉得这种考虑是偏执的。
答案 1 :(得分:4)
pdf文档主要是指来自对象ctor和初始化顺序的异常,以及静态或动态链接的库。
我在代码中看到的唯一的例外危险是,如果std :: string的ctor在调用它时会抛出。
如果你真的想要安全,你可以使用静态const char * mystring,而不是调用C ++ ctor。
还有一个代码存在于共享库中,然后需要将其放在进程的地址空间中。 如果你不使用复杂的ctors(可以扔掉的ctors),我不会认为这是一个主要问题。
答案 2 :(得分:4)
唯一的“问题” - 如果你可以调用它 - 我在你的代码中看到的是你不必要地将已经不变的数据复制到一个动态分配的缓冲区(这是正式) 不变,但实际上并非如此)。它使用了两倍的物理内存,并进行了不必要的复制。
重要吗?几乎可以肯定,没有。即使在“相当有限的内存”系统中,现在也不会从执行时间的角度来看,也不会通过其内存消耗来注意这一点。
对于异常,当然技术上是std::string
必须使 失败的分配,因此构造函数可以扔掉,你就无法抓住它。但请务必现实
几乎可以保证不会发生这种情况,但即使它确实如此......如果在程序启动时为一些字符串分配内存的事情很简单,那么在一个完全不同的规模上你会遇到一个非常非常严重的问题!登记/>
此外,正如在上面另一个答案的评论中所指出的:假设确实发生了这种情况,你打算怎么做呢?该程序完全无法运行,所以你可以想象的杀死程序并不是很多。
现在,由于C ++ 17并不遥远且string_view
已经在std::experimental
中可用于几个主流编译器,还有另一件事你可以尝试:使用正确的东西
string_view
与string
相反,不会分配非常量内存,将常量数据复制到其中,然后假装它是常量。相反,它将直接管理指向常量数据的指针,这就是全部
这样,您的常量确实(不仅仅是正式)常量,没有分配,没有异常的可能性,也没有双重内存使用。在大多数情况下,它仍然看起来和闻起来像string
。唯一值得注意的差异是string_view
不能保证nul-termination(但它指向的字符常量,所以这是无关紧要的),以及它真正常量的事实,不可修改......这正是你想要的。