如果您已经知道变量应该是常量,为什么还要使用关键字 const?

我正在阅读的许多书籍使用关键字 const时,一个变量的值不应该被修改。除了向代码读者指定如果修改这个变量可能会导致错误之外(可以使用注释来做到这一点) ,为什么需要将这个关键字作为任何编程语言的一部分呢?在我看来,如果你不想修改变量,那就别修改。

有人能给我解释一下吗?

6896 次浏览

它告诉编译器不应该修改变量,因此如果有人编写了修改变量的代码,编译器会将其标记为错误。

除了向代码读者指定如果修改此变量可能会导致错误之外(可以使用注释来完成此操作)

不是“可能”; 威尔会导致程序错误。

  • C + + 编译器将通过编译失败和诊断消息(“编译器错误”)强制执行它,不需要注释;
  • 一个 C 编译器会强制执行 大部分是,尽管它的标准库由于遗留问题(如 strchr)而有漏洞,而且它有一些相当宽松的隐式转换规则,可以让你在不太容易意识到它的情况下删除 const。然而,编译成功并不意味着没有错误; 不幸的是,是的意味着错误可能是程序中的细微错误,也可能是重大的、引人注目的崩溃。

无论哪种方式,您的程序都保证在其中包含 错误

在我看来,如果你不想修改变量,那就别修改。

这很好,但没有人是完美的。程序员会犯错。这样编译器就不会犯错误(至少不会经常犯错) ,可以指出错误。

当您使用一些数据变量时,它的用途非常特殊,这些数据变量离创建它的地方有很多很多行代码。距离越远,就越容易修改它,而不必意识到你不应该这样做。对于大型的、复杂的代码库,这只是必须的。

您在代码库中获得了 可证明性正确稳定的一个新度量,以及一大块可能导致非常微妙和令人讨厌的 bug 的原因。在某些情况下,当编译器知道某些值在编译之后不会改变时,编译器也可以使用大量的 优化机会

我们可以列出一整天的优势,但是,真的,你不会完全 格鲁克它,直到你已经在这样一个代码库工作。

事实上,在一个完美的世界中,默认情况下,所有变量都是 const,您需要使用关键字 mutable声明它们,以便能够更改它们。C + + 是倒过来的。

至少在 C + + 中,const有一些用途,而不仅仅是向其他程序员说明您的意图。

const还可以告诉编译器一些事情。例如,接受引用(如: void f(T &t);)的函数不能接受临时对象作为其参数。为了让它这样做,您需要 const限定参考,如: void f(T const &t)

同样,要调用 const 对象上的成员函数,成员函数必须是 const限定的,如: void T::foo() const {}

在嵌入式系统中,const 可以意味着更多,可能告诉编译器在哪里定位有问题的对象(把它放在 ROM 和 RAM 中)。const本身并不一定足以告诉它“把这个对象放入 ROM”,但它仍然常常是一个先决条件。

同样(在 C + + 11下) const 告诉编译器线程安全

现在,毫无疑问,您可以定义一些其他语言,这些语言(在其他方面)与不以这些方式使用 const的 C 或 C + + 有一些相似之处。不过,结果将是一种与上述两种语言都大不相同的语言。在不知道你的意图的情况下,我们不可能知道它的结果,但是它可能会更接近于 Java 或者 C # (对于一些例子来说) ,这两者在某些方面有点类似于 C 和 C + + ,但是不是这一个(例如,不要像 C 和 C + + 那样使用 const)。

两个原因:

  1. 编译器强制执行的文档
  2. 编译器优化

这里是一个很好的 解释从伊恩兰斯泰勒(谁工作的 gccgold链接器) :

Const 的第一个意思对程序有实际的影响。声明了 const 的变量可以与未声明 const 的变量进行不同的编译。

另一方面,const 的第二个含义实际上是编译器强制的文档。如果尝试使用常量限定指针更改值,但声明这样的指针不会更改生成的代码,则编译器将发出错误。

除了在其他答案中已经讨论过的通常的编程考虑之外,有一件事情让我担心,那就是态度:

在我看来,如果你不想修改一个变量,简单来说 不要。

一个普遍的经验法则是,编写代码的成本的20% 花费在开发阶段。另外80% 的时间花在代码的升级、维护等生命周期中。这意味着许多其他人将在您的代码上工作,而不是您自己。

在开发过程中花费时间来避免多年后的问题是一项很好的投资。这项工作包括: 编写注释; 定义常量; 编写依赖于晦涩语言结构的 没有显式代码。

另外,@worldboss,我听到一些不宽容的声音。正如其他一些人所评论的那样,碳单元会犯错误,而硅单元可以做的任何有助于避免错误的事情都是值得赞赏的。

考虑这样一个场景,即在整个项目中多次使用相同的常量,并且在所有地方都要对其进行硬编码。现在您突然需要将常数的值更改为另一个值,因此在所有位置进行更改将非常繁忙。

所以我认为让你的代码更易于维护肯定是原因之一。

编译器可以进行大的优化,因为它知道变量不会被更改: 它不是存储在内存中,而是直接写入到可执行操作码中。

例如: 你有 a 和 b,你想把它们加起来,你就得 a + b。如果将 a 声明为 const,并且值为3,程序将生成3 + b,这将节省内存和周期,因为它不需要检索 a 值。

问题是你的编译器不能预先知道变量是否是常量,当然它可以分析整个代码并检查你是否修改了这些变量,但它不能100% 确定,因为未来的代码也可以修改它。

下面是一个简单的 C 语言例子:

void PrintList(const struct List *l);
void SortList(struct List *l);
int  CmpList(const struct List *a, const struct List *b);
void AppendList(struct List *l, struct List *m);
void PushList(struct List *l, struct ListNode *n);
void PopList(struct List *l, struct ListNode *n);

这里我们有一小组函数,它们使用某种类型的节点列表。首先,在不知道函数名的情况下,我们可以立即看到哪些函数以某种方式改变了列表,哪些没有。与标准库中的函数一样,const函数不会更改数据,也不允许用它们更改数据。C 编译器会尝试保持指向传递给函数的数据的指针的 const-ness。因此,在这种情况下,我可以合理地确信,在运行时调试时,比较两个列表并不是破坏它们的函数,因为我已经保护自己免受数据意外修改的影响。;)

关键字 const对团队和长期项目非常有用。我会给你几个例子,这些应该解释值的 const关键字。

让我们说现在我创建的 lib 将用于进一步的项目。因此,这意味着今天编写的代码在几年后需要被信任,在这样一段时间内,我可能会忘记哪个变量不应该被修改(同事们甚至不知道什么可以修改,什么不能)。因此,这个简短的例子解释了为什么要使用 const

说到评论,当最后期限到来的时候,还有很多东西没有工作,每个功能的评论只是浪费时间。然而在某些情况下,评论是必须的,因为第一个问题(截止日期)的评论可能不会被读取,因为大多数评论是无用的,但是重要的评论也会被跳过。因此,最好使用 const关键字,它会导致编译错误,并指出你的问题,然后写和阅读大量的评论。

常量变量只是允许您编写更具可读性的代码。

const在几乎所有语言中的最大用途是允许我们使用名称来引用常量值,这样你就可以用流利的语言告诉其他人这个名称指的是什么,而不需要在代码中添加注释,从而节省读者了解参数类型和参数特性的时间和精力。当然,如果您的常量值在整个代码中得到重用,您也会从中受益。这样的代码可能更容易理解:

processPages(LETTER_PAPER_WIDTH, LETTER_PAPER_HEIGHT);

更重要的是:

processPages(215.9, 279.4); // 8.5 x 11 Inches in millimeters for Letter Papers

在上面的例子中,您需要理解每个参数是什么,它的单元和解释值的类型,并且您还需要根据注释对它进行验证,因为像这样的冗余注释(那些重播编码内容的注释)不是一个可靠和有用的注释(根据 Robert Martin 在 Clean Code: http://goo.gl/5EyY中的说法,是一个糟糕的注释)。

这是一个困难的问题,因为它是基于信念。其中一个信念是,只要添加更多的代码,就可以保护代码不受某些变更的影响。当然,编译器会使用额外的代码来检查一切是否正常。

我认为这并不总是正确的,你不能保护你的代码对抗你自己或你的开发团队只是添加关键字,事实上有很多语言没有任何 const,public,private,protected,inside,int,float,double 关键字,这并不意味着他们不是好语言。

同样的情况也发生在一些代码模式上,为什么人们浪费这么多时间讨论单例模式?如果希望只有一个实例,那么只需要创建一个实例,仅此而已。同样的思维模式无处不在,看看10年前发表的防御性编程文章,再次提出了用代码保护代码的想法。

在某种程度上,您必须决定在哪里设置职责,是由开发人员负责还是由编译人员负责。然而,无论是编译器还是其他任何工具都不能针对开发人员保存代码,因此许多关键字毫无价值,或者仅仅是与其他开发人员进行交流的一种方式。