如何在 C++ 中声明字符串和常量非 POD 数据的全局静态数组?

How to declare global static array of strings and const non-POD data in C++?

提问人:God I Am Clown 提问时间:11/4/2023 最后编辑:God I Am Clown 更新时间:11/4/2023 访问量:171

问:

我需要在文件“misc.h”中制作常量全局字符串数组。我真的不明白这应该如何做。如果它只是一个字符串,我会这样声明:

// misc.h
extern const char* str;

// misc.cpp
//static const char* str = "some sring"; invalid because of extern linkage 
const char* str = "some string";

如果我想要一个字符串数组,首先想到的是:

extern const char* strings[];

数组的大小在编译时是已知的,通常 将由编译器从初始值设定项中推断出来, 但是这里的初始化将(据我了解)在另一个编译单元 misc.cpp 中(数组非常大,我不想每次添加功能和重新编译代码时都重新计算它的大小)。我应该如何处理这种情况?
编辑:这个问题中的所有字符串和所有内容都是不可变的,不需要标准库中的任何功能。


关于同一主题的第二个问题是我应该如何在同一文件中声明常量哈希映射(更具体地说)?我还需要它是全局静态的。我不是在构建一个库,这个哈希映射服务器是我的应用程序的核心功能,所以让它成为全局静态应该是合适的。我知道有宏,但它用于防止数据争用,而我的哈希映射根据定义是只读的。我听说过内联变量,但我并不真正理解它们 - 我应该尝试在那里挖掘吗?声明和使用此类变量的最佳方法是什么?
const QHashQ_GLOBAL_STATIC

C++ 数组 字符串 qt 全局变量

评论

1赞 user12002570 11/4/2023
你说“数组”,但你声明了“指向数组的指针”,为什么?
0赞 Weijun Zhou 11/4/2023
extern const char* strings[];是有效的。这里不需要给出尺寸。你可以在你的misc.cpp中做。const char* strings[]={"a"};
0赞 Darius 11/4/2023
如何为大小公开另一个变量,例如?extern int strings_size;
0赞 user7860670 11/4/2023
您应该在头文件中声明数组 getter 函数,而不是变量声明。回到那里是个好主意。因此,数组大小可以从初始值设定项中推断出来。另一方面,创建一个全局对象是一个糟糕的主意,因为它容易出现 SIOF。extern::std::spanQHash
1赞 user17732522 11/4/2023
static在第一个示例中的定义是错误的。它给出了可变的内部链接,而你已经给了它外部链接。这是不兼容的。编译器应该抱怨链接不匹配。extern

答:

1赞 user12002570 11/4/2023 #1

我需要在文件“misc.h”中制作字符串的全局数组

您可以使用指向数组的指针。在此方法中,无需在定义中使用关键字。const charextern

其他

//declaration-----v-------->note the pointer in this example
extern const char *str[];

杂项.cpp

//definition, note no need for extern keyword here.
const char *str[] = {"some"," string"}; 

工作演示


另外,使用全局变量的优点和缺点是什么?[关闭]

2赞 user17732522 11/4/2023 #2

对于 C++ 中类型的任何不可变全局常量,您可以简单地编写cC

const C c = /*initializer*/;

在标题中。 默认情况下,变量具有内部链接。每个翻译单元都会有所不同,并且不会出现任何重新定义错误。(但请注意,这在 C 中是不同的。constc

更好的是

constexpr C c = /*initializer*/;

假设该类型支持常量表达式初始化。这保证了在运行时不会发生初始化,并且该变量可以在其他常量表达式中使用。在运行时可能会有动态初始化,这可能会导致初始化顺序出现问题,尽管这在单个翻译单元内比在多个翻译单元中更受关注。( 暗示在类型上。Cconstconstexprconst

在少数情况下,该类型可能支持常量表达式初始化,但不支持常量销毁。在这种情况下,仍然可以使用

constinit const C c = /*initializer*/;

constinit如果无法执行常量初始化,将导致声明失败,同时仍允许非恒量销毁。(不过,它并不意味着类型,因此必须显式添加。const

如果无法进行常量初始化,并且初始化顺序是一个潜在的问题,则根本不应使用全局变量。相反,可以使用函数中的局部变量。static

如果需要依赖于每个翻译单元中的相同对象,则可以在标题中添加定义。cinline


对于字符串数组:

constexpr const char* c[] = {"string1", "string2", "string3"};

constexpr std::array c = {"string1", "string2", "string3"};

(或这些类型的声明语法的任何其他变体。您也可以使用 ,但从 C++23 开始,它目前不支持常量初始化。但是,使用的两个声明的变体是可能的。std::stringstd::string_view

在标头中执行此初始化还有一个好处,即每个转换单元都会自动知道数组的大小。在单个翻译单元中使用 和 意味着其他翻译单元不知道大小,或者您必须在声明中手动输入正确的大小。extern