C++ 静态常量字符串(类成员)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1563897/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Static constant string (class member)
提问by lb.
I'd like to have a private static constant for a class (in this case a shape-factory).
我想要一个类的私有静态常量(在这种情况下是一个形状工厂)。
I'd like to have something of the sort.
我想要这样的东西。
class A {
private:
static const string RECTANGLE = "rectangle";
}
Unfortunately I get all sorts of error from the C++ (g++) compiler, such as:
不幸的是,我从 C++ (g++) 编译器中得到了各种错误,例如:
ISO C++ forbids initialization of member ‘RECTANGLE'
invalid in-class initialization of static data member of non-integral type ‘std::string'
error: making ‘RECTANGLE' static
ISO C++ 禁止成员“RECTANGLE”的初始化
非整数类型“std::string”的静态数据成员的类内初始化无效
错误:将“矩形”设为静态
This tells me that this sort of member design is not compliant with the standard. How do you have a private literal constant (or perhaps public) without having to use a #define directive (I want to avoid the uglyness of data globality!)
这告诉我这种成员设计不符合标准。如何在不必使用 #define 指令的情况下拥有私有常量(或可能是公共的)(我想避免数据全局性的丑陋!)
Any help is appreciated.
任何帮助表示赞赏。
回答by AnT
You have to define your static member outside the class definition and provide the initializer there.
您必须在类定义之外定义静态成员并在那里提供初始化程序。
First
第一的
// In a header file (if it is in a header file in your case)
class A {
private:
static const string RECTANGLE;
};
and then
进而
// In one of the implementation files
const string A::RECTANGLE = "rectangle";
The syntax you were originally trying to use (initializer inside class definition) is only allowed with integral and enum types.
您最初尝试使用的语法(类定义中的初始化程序)只允许用于整型和枚举类型。
Starting from C++17 you have another option, which is quite similar to your original declaration: inline variables
从 C++17 开始,您有另一个选项,它与您的原始声明非常相似:内联变量
// In a header file (if it is in a header file in your case)
class A {
private:
inline static const string RECTANGLE = "rectangle";
};
No additional definition is needed.
不需要额外的定义。
Or instead of const
you can declare it constexpr
in this variant. Explicit inline
would no longer be necessary, since constexpr
implies inline
.
或者,const
您可以constexpr
在此变体中声明它。inline
不再需要显式,因为constexpr
意味着inline
。
回答by abyss.7
In C++11 you can do now:
在 C++11 中,您现在可以执行以下操作:
class A {
private:
static constexpr const char* STRING = "some useful string constant";
};
回答by sellibitze
Inside class definitions you can only declarestatic members. They have to be definedoutside of the class. For compile-time integral constants the standard makes the exception that you can "initialize" members. It's still not a definition, though. Taking the address would not work without definition, for example.
在类定义中,您只能声明静态成员。它们必须在类之外定义。对于编译时积分常量,标准例外,您可以“初始化”成员。不过,它仍然不是一个定义。例如,在没有定义的情况下,获取地址是行不通的。
I'd like to mention that I don't see the benefit of using std::string over const char[] for constants. std::string is nice and all but it requires dynamic initialization. So, if you write something like
我想提一提,我没有看到使用的std :: string在为const char []的利益为常数。std::string 很好,但它需要动态初始化。所以,如果你写这样的东西
const std::string foo = "hello";
at namespace scope the constructor of foo will be run right before execution of main starts and this constructor will create a copy of the constant "hello" in the heap memory. Unless you really need RECTANGLE to be a std::string you could just as well write
在命名空间范围内,foo 的构造函数将在 main 开始执行之前运行,并且该构造函数将在堆内存中创建常量“hello”的副本。除非你真的需要 RECTANGLE 成为 std::string 你也可以这样写
// class definition with incomplete static member could be in a header file
class A {
static const char RECTANGLE[];
};
// this needs to be placed in a single translation unit only
const char A::RECTANGLE[] = "rectangle";
There! No heap allocation, no copying, no dynamic initialization.
那里!没有堆分配,没有复制,没有动态初始化。
Cheers, s.
干杯,S。
回答by GManNickG
This is just extra information, but if you really want the string in a header file, try something like:
这只是额外的信息,但如果您真的想要头文件中的字符串,请尝试以下操作:
class foo
{
public:
static const std::string& RECTANGLE(void)
{
static const std::string str = "rectangle";
return str;
}
};
Though I doubt that's recommended.
虽然我怀疑这是推荐的。
回答by Oz Solomon
In C++ 17 you can use inline variables:
在 C++ 17 中,您可以使用内联变量:
class A {
private:
static inline const std::string my_string = "some useful string constant";
};
Note that this is different from abyss.7's answer: This one defines an actual std::string
object, not a const char*
请注意,这与abyss.7 的答案不同:这个定义了一个实际的std::string
对象,而不是一个const char*
回答by aJ.
To use that in-class initialization syntax, the constant must be a static const of integral or enumeration type initialized by a constant expression.
要使用该类内初始化语法,常量必须是由常量表达式初始化的整数或枚举类型的静态常量。
This is the restriction. Hence, in this case you need to define variable outside the class. refer answwer from @AndreyT
这就是限制。因此,在这种情况下,您需要在类之外定义变量。参考@AndreyT的答案
回答by Marko Mahni?
The class static variables can be declaredin the header but must be definedin a .cpp file. This is because there can be only one instance of a static variable and the compiler can't decide in which generated object file to put it so you have to make the decision, instead.
类静态变量可以在头文件中声明,但必须在 .cpp 文件中定义。这是因为静态变量只能有一个实例,编译器无法决定将它放在哪个生成的目标文件中,因此您必须做出决定。
To keep the definition of a static value with the declaration in C++11 a nested static structure can be used. In this case the static member is a structure and has to be defined in a .cpp file, but the values are in the header.
为了使用 C++11 中的声明保持静态值的定义,可以使用嵌套的静态结构。在这种情况下,静态成员是一个结构,必须在 .cpp 文件中定义,但值在标题中。
class A
{
private:
static struct _Shapes {
const std::string RECTANGLE {"rectangle"};
const std::string CIRCLE {"circle"};
} shape;
};
Instead of initializing individual members the whole static structure is initialized in .cpp:
整个静态结构不是初始化单个成员,而是在 .cpp 中初始化:
A::_Shapes A::shape;
The values are accessed with
这些值通过访问
A::shape.RECTANGLE;
or -- since the members are private and are meant to be used only from A -- with
或者 -- 因为成员是私有的,并且只能从 A 使用 -- 与
shape.RECTANGLE;
Note that this solution still suffers from the problem of the order of initialization of the static variables. When a static value is used to initialize another static variable, the first may not be initialized, yet.
请注意,此解决方案仍然存在静态变量初始化顺序的问题。当一个静态值被用来初始化另一个静态变量时,第一个可能还没有被初始化。
// file.h
class File {
public:
static struct _Extensions {
const std::string h{ ".h" };
const std::string hpp{ ".hpp" };
const std::string c{ ".c" };
const std::string cpp{ ".cpp" };
} extension;
};
// file.cpp
File::_Extensions File::extension;
// module.cpp
static std::set<std::string> headers{ File::extension.h, File::extension.hpp };
In this case the static variable headerswill contain either { "" } or { ".h", ".hpp" }, depending on the order of initialization created by the linker.
在这种情况下,静态变量头将包含 { "" } 或 { ".h", ".hpp" },具体取决于链接器创建的初始化顺序。
As mentioned by @abyss.7 you could also use constexpr
if the value of the variable can be computed at compile time. But if you declare your strings with static constexpr const char*
and your program uses std::string
otherwise there will be an overhead because a new std::string
object will be created every time you use such a constant:
正如@abyss.7 所提到的,constexpr
如果可以在编译时计算变量的值,您也可以使用。但是如果你声明你的字符串static constexpr const char*
并且你的程序使用std::string
否则会有开销,因为std::string
每次使用这样的常量时都会创建一个新对象:
class A {
public:
static constexpr const char* STRING = "some value";
};
void foo(const std::string& bar);
int main() {
foo(A::STRING); // a new std::string is constructed and destroyed.
}
回答by chikuba
possible just do:
可能只是这样做:
static const std::string RECTANGLE() const {
return "rectangle";
}
or
或者
#define RECTANGLE "rectangle"
回答by user2806882
You can either go for the const char*
solution mentioned above, but then if you need string all the time, you're going to have a lot of overhead.
On the other hand, static string needs dynamic initialization, thus if you want to use its value during another global/static variable's initialization, you might hit the problem of initialization order. To avoid that, the cheapest thing is accessing the static string object through a getter, which checks if your object is initialized or not.
您可以选择const char*
上面提到的解决方案,但是如果您一直需要字符串,那么您将有很多开销。
另一方面,静态字符串需要动态初始化,因此如果你想在另一个全局/静态变量的初始化过程中使用它的值,你可能会遇到初始化顺序的问题。为了避免这种情况,最便宜的方法是通过 getter 访问静态字符串对象,它检查您的对象是否已初始化。
//in a header
class A{
static string s;
public:
static string getS();
};
//in implementation
string A::s;
namespace{
bool init_A_s(){
A::s = string("foo");
return true;
}
bool A_s_initialized = init_A_s();
}
string A::getS(){
if (!A_s_initialized)
A_s_initialized = init_A_s();
return s;
}
Remember to only use A::getS()
. Because any threading can only started by main()
, and A_s_initialized
is initialized before main()
, you don't need locks even in a multithreaded environment. A_s_initialized
is 0 by default (before the dynamic initialization), so if you use getS()
before s is initialized, you call the init function safely.
记住只使用A::getS()
. 因为任何线程只能由 启动main()
,并且A_s_initialized
在 之前被初始化main()
,所以即使在多线程环境中也不需要锁。A_s_initialized
默认为 0(在动态初始化之前),因此如果使用getS()
before s 初始化,则可以安全地调用 init 函数。
Btw, in the answer above: "static const std::string RECTANGLE() const" , static functions cannot be const
because they cannot change the state if any object anyway (there is no this pointer).
顺便说一句,在上面的答案中:“ static const std::string RECTANGLE() const”,静态函数不能,const
因为它们无论如何都不能改变状态(如果有任何对象)(没有 this 指针)。
回答by Leandro T. C. Melo
The current standard only allows such initialization for static constant integral types. So you need to do as AndreyT explained. However, that will be available in the next standard through the new member initialization syntax.
当前标准仅允许对静态常量整数类型进行此类初始化。所以你需要按照 AndreyT 的解释去做。但是,这将通过新成员初始化语法在下一个标准中可用。