【问题标题】:When should I use static data members vs. const global variables?什么时候应该使用静态数据成员与 const 全局变量?
【发布时间】:2015-12-10 10:49:54
【问题描述】:

声明 const 全局变量已被证明有助于确定 API 的某些功能参数。例如,在我的 API 上,数值精度运算符的最小阶数是 2;因此,我声明:

const int kDefaultOrderAccuracy{2};

作为一个全局变量。将其设为描述这些运算符的类的 static const 公共数据成员会更好吗?一般来说,什么时候选择一个比另一个更好?

【问题讨论】:

  • 您能多说几句关于已被证明对确定一些功能参数很有用吗?
  • ...默认参数呢?
  • 这取决于你的API,但我认为一个常见的方法如下。如果它只在一个类中使用,则使其成为静态数据成员或成员enum。如果在整个 API 中使用它,请使用宏或枚举,f.ex。 enum class OrderAccuracy { kDefault = 2, /* ... */ };.

标签: c++11 global-variables declaration static-members linkage


【解决方案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,因为定义不是唯一的,因为它使用命名空间静态变量:kDefaultOrderAccuracy定义指定的对象取决于编译它的 TU。

类的静态成员具有外部链接:

struct constants {
  static const int kDefaultOrderAccuracy{2};
};

inline int f(int x) {
  return max(constants::kDefaultOrderAccuracy, x); // OK
}

程序中只有一个constants::kDefaultOrderAccuracy

您还可以使用命名空间级别的全局常量对象:

extern const int kDefaultOrderAccuracy;

【讨论】:

    【解决方案2】:

    上下文总是很重要的。

    • 回答这样的问题。
    • 也用于命名。

    如果您作为读者(共同编码人员)需要猜测标识符的含义,则开始寻找更多上下文,这可能会通过 API 文档得到支持,通常包含在体面的 IDE 中。但是,如果您没有提供一个非常棒的 AP​​I 文档(我从您的问题中读到了这一点),那么您获得的唯一上下文就是查看您的声明的放置位置。

    在这里,您可能对包含库、子目录、文件、命名空间或类的名称感兴趣,最后对所使用的类型感兴趣。

    如果阅读kDefaultOrderAccuracy,我会看到很多上下文编码(默认顺序准确度),其中 Order 可能与销售或排序相关,而 k 编码对我没有任何意义。只是为了让您从不同的角度看待您的实际问题。 C/C++ 标识符的语法很差:它们仅限于复合词的规则。

    全局标识符的这种限制是我主要避免全局变量,甚至是常量,有时甚至是类型的最重要原因。如果它的含义仅限于给定的上下文,则在此上下文中中定义一个事物。有时您首先必须创建此上下文

    您的解释包含一些未使用的上下文:

    • 数值运算符
      • 最小精度(顺便说一句:最小并不意味着默认

    将定义放入正确的类的问题与为全局找到正确位置的问题没有太大区别:您必须找到/创建正确的头文件(和/或命名空间)。

    作为旁注,您可能有兴趣了解enum 也可用于获取廉价的编译时常量,并且枚举也可以放入类中(或namespaces)。 scoped enumeration 也是您在引入全局常量之前应该考虑的一个选项。与封闭类定义一样,:: 是一种标点符号,它分隔的不仅仅是 _ 或字内 caseChange

    附录:

    如果您有兴趣为您的操作提供一个有用的默认行为,可以被您的用户覆盖,default arguments 可能是一个选项。如果您的 API 提供运算符,您应该研究标准 I/O 流的 input/output manipulators 是如何工作的。

    【讨论】:

    • k 字母是匈牙利表示法中常量的常用前缀,因此对于大多数开发人员来说是可以理解的。
    • k 字母没有添加有关含义/上下文/分组的信息。
    【解决方案3】:

    我的猜测是: const 根据每次使用的数据值的大小(例如“mov ah, const value”)占用内联内存,这可以是一个非常短的命令,总体大小,总体而言,基于输入值。 而静态值占用一个完整的数据类型,通常是 int,无论在当前系统上对于每个静态可能是什么,可能更多,另外它可能需要一个完整的内存访问值来访问数据,例如 mov ah, [内存指针],这通常是系统上的 int 大小,用于每次使用(使用完整的类可能会更复杂)。然而静态仍然被声明为 const,因此它的行为可能与正常的 const 类型相同。

    【讨论】:

    • 这并没有提供问题的答案。一旦你有足够的reputation,你就可以comment on any post;相反,provide answers that don't require clarification from the asker。 - From Review
    • 我要求澄清什么?我唯一不确定的是如何处理 const static 。他们提供更多信息不会向我提供我不确定的信息。如果 const static 的处理方式与 const 相同,则差异没有意义(或没有差异),如果 const static 以更复杂的方式处理,如前所述,则 const static 会增加额外的开销。坚持使用 const 不会比 const static 增加移动开销(至少我希望不会),但使用 const static 可能更自然。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-01
    • 1970-01-01
    相关资源
    最近更新 更多