为什么我们不能有非常量的类级静态变量?
Why can't we have non-const class-level static variables?
为什么Visual c++编译器拒绝编译这段代码?
我显然知道错误是:
错误C2864:
Singleton<T>::p
:
只能在类中初始化静态const整型数据成员
, ?(即,是否存在技术不允许的原因?)
这是编译器特有的行为还是标准强制要求的?
在全局作用域似乎没问题,那么为什么在类作用域不行呢?
似乎并不是所有的编译器都介意这个
还有,解决这个问题的正确方法是什么?
template<typename T>
struct Singleton
{
static T *p = 0; // Error C2864
static T *getInstance() { /*...*/ return p; }
};
这是标准行为。只有静态const整型成员可以在没有适当定义的情况下初始化。所有其他类型都需要在某个地方定义,并且在定义点编写初始化:
template<typename T>
struct Singleton {
static T *p;
static T *getInstance() { /*...*/ return p; }
};
template<typename T>
T *Singleton<T>::p = 0;
对象必须在某处定义。如果在类中定义它们,则在头文件中定义它们,并且为包含它们的每个编译单元获得不同的对象。这对于const整型来说是宽松的,如果你没有定义它们,编译器就会用它的字面值替换它。如果没有提供定义,获取此类静态const整型的地址仍然会导致链接器错误。
可以使用这种类型的变量,但不能在类定义中初始化它。唯一可以按您要求的方式初始化的变量类型是static const
。
类定义的固定版本删除了= 0
,并将其添加到类定义下面:
template<typename T>
T *Singleton<T>::p = 0;
这是标准行为。我不确定是否有技术原因,我的猜测是为了与实例成员保持一致(也不能以这种方式初始化)。当然,实例变量有构造函数初始化列表。
正如每个人指出的那样,你不能在类的主体中定义非const,非整型(至少在c++ 03中不能,它在c++ 11中改变了,但我不确定具体是如何改变的)。然而,你可以用不同的方法来清理。
template<typename T>
struct Singleton {
static T* getInstance() {
static T* p = NULL;
/*...*/
return p;
}
};
声明应该放在头文件中,在那里它们将被编译许多次-每个包含它们的地方。
静态变量应该只有一个定义,这样在整个程序中只有一个副本。这意味着它需要位于源文件(.cpp)中。赋值需要放在那个位置
静态常数整数是上述规则的例外,因为它们可以成为编译时常数。当使用它们时,用文字值代替类成员。
不能像这样在类体中分配非静态类。相反,应该在类之外赋值(通常在您的cpp文件中)
template<typename T>
struct Singleton {
static T *p;
static T *getInstance() { /*...*/ return p; }
};
template<typename T>
T *Singleton<T>::p = 0;
有趣的问题不是你问的问题,而是相反的问题:
为什么允许在声明中为const整型静态成员赋值?
问题的重要部分是声明。变量获得的值是在变量定义中设置的,这与类的非const或非整型静态成员一致,在类中只提供声明。初始化器值在定义中提供,该定义位于类定义之外,通常在.cpp中,保证它将定义在单个翻译单元中。
但是为什么整型静态常量可以在声明中有值呢?
出于实际原因。编译器可以使用整型常量作为编译时常量,也就是说,它实际上可以在所有将该常量用作右值的地方(例如定义数组的大小时)替换该常量的值来代替标识符。但是,如果值仅在单个翻译单元的定义中出现,则编译器不可能在所有其他翻译单元中使用它。例如:
// fq.h
struct fixed_queue {
static const std::size_t max_elements; // [1]
int data[ max_elements ]; // Error: How big is data??
};
// fq.cpp
#include "fq.h"
const std::size_t fixed_queue::max_elements = 10;
如果max_elements
不允许在声明[1]中有一个值,那么您将不能使用该常量来定义数组data
的大小,这是一个非常明智的使用静态常量。
为什么不将其扩展到所有其他情况?
因为它似乎没有多大意义…在类定义中提供的值不能被编译器在任何其他情况下使用,因此它是不需要的,所以只有整型常量需要被区别对待。
原因是非整型、非const值需要一个内存位置。
const int
可以由编译器静态处理,并直接构建到某些机器指令,浮点数和更多的外来对象需要一个地方驻留,因为机器指令只根据它们的地址进行操作。
原则上,语言可以允许这样做,但这意味着要么生成额外的对象并使二进制文件膨胀(对于const来说是ok的),要么使编译器编写非const的工作变得困难:必须删除冗余副本以保持单定义规则(顺便说一下,这就是模板实例化必须做的)。
- 在 .h 文件中的类中声明静态变量和在.cpp文件中声明"global"变量有什么区别
- 模板基类中的静态变量
- 类和静态变量
- 不同作用域中的静态变量和全局变量
- 静态变量声明和定义
- 是否可以依赖函数范围的静态变量来执行程序关闭期间调用的方法?
- 在类中继承静态变量?
- "local scope"中的 C++ 初始化静态变量
- 使用静态变量的递归调用的不同输出
- 复制文件流C++静态变量
- 跨模板化函数编译的静态变量
- C++编译器是否优化了顺序静态变量读取?
- C++,每个循环初始化一个新的静态变量
- (为什么)我们可以在初始化中将非静态类成员分配给静态变量吗?
- 这些语句是否等效(静态变量、常量变量和泛型)
- 程序如何知道静态变量是否需要初始化?
- 类外的静态变量实例化
- 无法解析静态变量
- 函数局部静态变量:从性能角度来看的优点/缺点
- 访问从 CPP 文件到其他头文件的静态变量