声明 const 全局变量已证明对确定API的某些功能参数很有用。例如,在我的API上,运算符的最小数值精度顺序为2;因此,我宣布:
const int kDefaultOrderAccuracy{2};
作为全局变量。将它作为描述这些运算符的类的static const
公共数据成员会更好吗?一般来说,最好选择一个而不是另一个?
答案 0 :(得分:1)
const int kDefaultOrderAccuracy{2};
是静态变量的声明:kDefaultOrderAccuracy
具有内部链接。将带有内部链接的名称放在标头中显然是一个非常糟糕的主意,这使得在具有相同或其他标头的外部链接的其他代码中违反一个定义规则(ODR)非常容易,尤其是当该名称用于内联或模板函数的主体中:
在f.hpp内部:
template <typename T>
const T& max(const T &x, const T &y) {
return x>y ? x : y;
}
inline int f(int x) {
return max(kDefaultOrderAccuracy, x); // which kDefaultOrderAccuracy?
}
在两个TU(转换单元)中加入f.hpp
后,您违反了ODR ,因为定义不是唯一的,因为它使用了名称空间静态变量:其中{定义指定的{1}}对象取决于编译该对象的TU。
类的静态成员具有外部链接:
kDefaultOrderAccuracy
程序中只有一个struct constants {
static const int kDefaultOrderAccuracy{2};
};
inline int f(int x) {
return max(constants::kDefaultOrderAccuracy, x); // OK
}
。
您还可以使用命名空间级别的全局常量对象:
constants::kDefaultOrderAccuracy
答案 1 :(得分:0)
语境总是很重要。
如果您作为读者(共同编码人员)需要猜测标识符的含义,您就会开始寻找更多上下文,这可能通过API文档得到支持,通常包含在体面的IDE中。但是如果你没有提供一个非常好的API文档(我从你的问题中读到这个),你得到的唯一上下文就是查看你的声明所在的位置。
在这里,您可能对包含的库,子目录,文件,命名空间或类的名称感兴趣,并且最后在所使用的类型中也是如此。
如果我阅读kDefaultOrderAccuracy
,我会看到很多上下文编码(默认,订单,准确性< / em>),其中订单可能与销售或排序相关,而k
编码对我没有任何说明。只是为了让你从不同的角度看待你的实际问题。 C / C ++标识符的语法很差:它们仅限于复合词的规则。
全局标识符的这种限制是我主要避免全局变量,甚至是常量,有时甚至是类型的最重要原因。如果其含义仅限于给定的上下文,则在此上下文中定义。有时您首先必须创建此上下文。
您的解释包含一些未使用的背景:
将定义放入正确的类中的问题与为全局找到正确位置的问题没有太大区别:您必须找到/创建正确的头文件(和/或命名空间)。
作为旁注,您可能有兴趣了解同样可以使用enum
来获得廉价的编译时常量,并且还可以将枚举放入类(或namespaces)中。另外,scoped enumeration是在引入全局常量之前应该考虑的选项。与封闭类定义一样,::
是一种标点符号,可以分隔多个_
或一个词内caseChange
。
如果您有兴趣提供可由用户覆盖的操作的有用默认行为,default arguments可能是一种选择。如果您的API提供运算符,您应该研究标准I / O流的input/output manipulators 如何工作。
答案 2 :(得分:-3)
我的猜测是: const根据数据值的大小占用内联内存,例如每次使用的“mov ah,const value”,这可以是一个非常短的命令,总体上,基于输入值的整体大小。 静态值占用整个完整的数据类型,通常是int,无论当前系统对于每个静态,可能更多,加上它可能需要一个完整的内存访问值来访问数据,如mov啊,[内存指针],对于每次使用,通常是系统上int的大小(完整的类可能更复杂)。但静态仍然被声明为const,因此它的行为可能与普通的const类型相同。