不鼓励在C ++中使用常量吗?

时间:2012-09-26 20:36:39

标签: c++ coding-style

style guide对我有用,但我遇到了规则#5:

  

通常,应尽量减少这些常数的使用。在很多   实现价值作为方法的案例是更好的选择:

int getMaxIterations() // NOT: MAX_ITERATIONS = 25
{
    return 25;
}

我从风格的角度理解这个推理:你不仅要消除"喊叫"常量声明,但你也减少了正在使用的语言结构的数量(如果这是不正确的术语,请原谅我),使程序更容易理解。

然而,这种方法是否对编译器有贬义作用,或者是现代编译器(或者实际上是较旧的编译器......)能够足够前瞻以确定您的getMaxIterations函数每次都返回相同的数字?

事实上,在第二个想法中,编译器是否需要向前看?样式指南建议方法方法更好而不是使用常量值,我是否正确地猜测这是因为"常数"在其使用的任何范围内完成后,不需要将值保存在内存中吗?

总之,我的问题是:不鼓励使用常数值,如果是,为什么?

(对于奖励积分,将常数值声明为方法和常量之间的技术差异是什么?)

4 个答案:

答案 0 :(得分:4)

这是大多数编译器的内容。

据说,风格指南正在说明问题。它说不是这样做的:

#define FOO_MAX_ITERATIONS 25
struct Foo {
  void do_it() { for(int i = 0; i < FOO_MAX_ITERATIONS; i++) iterate(); }
};

应该是这样的:

struct Foo {
  int getMaxIterations() { return 25; }
  void do_it() { for(int i = 0; i < getMaxIterations(); i++) iterate(); }
};

正如您所看到的,从长远来看,它更加一致和可读,并且适用于未来的设计,例如当您从班级继承时。稍后,您可能希望在运行时修改getMaxIterations(),并且您不必像#define FOO_MAX_ITERATIONS someMethod()那样进行丑陋的黑客攻击。

如果您正在使用任何理智的C ++ 11编译器(即不是Visual Studio),则应另外声明此类函数:

struct Foo {
  constexpr int getMaxIterations() { return 25; }
  void do_it() { for(int i = 0; i < getMaxIterations(); i++) iterate(); }
};

注意在getMaxIterations()声明中的constexpr。这告诉C ++ 11编译器它是一个“常量表达式”,它可以在编译时进行评估。通过执行此操作,它可以在编译之前直接将getMaxIteratsion()替换为25,以及许多其他内容,例如允许您在其他编译时声明中使用它。

答案 1 :(得分:4)

Bertrand Meyer称之为“统一参考原则”(IIRC)的原因之一。

他使用了银行帐户和当前余额的示例。这应该是数据成员还是函数/方法?迈耶认为,在软件项目的整个生命周期中,这种类型的决策很可能会改变几次。因此,即使天平当前表示为数据成员,也应将其包装在getter中。然后,即使实现必须更改,接口也不必更改...因此此类的客户端与实现更改绝缘。

换句话说,即使这是一个恒定的现在,你可能会发现自己处于需要计算的地步。

并且,正如其他人所指出的那样,任何现代编译器(希望)都足够智能,它们将内联方法实现,并且不会因为它成为一种方法而导致性能损失。

答案 2 :(得分:3)

没有。事实上,它是鼓励constexpr之前的编译器(有许多,甚至是最新的MSVC)都不能将函数调用用作常量值。

std::array<int, getMaxIterations()> arr; // bad
std::array<int, MaxIterations> arr; // fine

那个指南是一堆错误的。考虑44

  

一个类的部分必须被公开,保护和私有[2] [3]。必须明确标识所有部分。不应该删除不适用的部分。

这是完全错误的。通常需要交错它们,因为公共API依赖于私有事物。这种严格的排序禁止使用几种API,纯粹是因为声明顺序。一个简单的例子是你返回一个私有类型 - 通常用于代理对象,表达式模板等,或者公共方法的实现依赖于私有模板方法,必须在使用之前完全定义它。

答案 3 :(得分:0)

在声明一个常量值和使用一种方法之间存在一个巨大的区别,就像这个风格指南所暗示的那样。

方法声明:

int getMaxIterations()
{
  return 25;
}

意味着获取getMaxIterations的值可以修改调用该方法的对象的状态。这意味着您无法了解const对象的最大迭代值。这也意味着该方法在多线程环境中调用可能不安全。这显然是不正确的,该方法应声明为:

int getMaxIterations() const;