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

时间:2013-08-10 00:37:45

标签: c++ c const keyword

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

有人可以为我澄清一下吗?

11 个答案:

答案 0 :(得分:97)

  

除了向代码的读者指定修改此变量可能导致错误(您可以使用注释执行此操作)

不是“可能”; 导致程序出错。

  • C ++编译器会使用编译失败和诊断消息(“编译器错误”)强制执行它,而不需要注释;
  • AC编译器将大部分强制执行,尽管其标准库因遗留漏洞而存在漏洞,例如strchr,并且它有一些相当宽松的隐式转换规则可以允许你放弃const而没有很容易地意识到这一点。但是,仅仅因为你有一个成功的编译并不意味着你没有错误;不幸的是,确实意味着错误可能是程序中的微妙错误,以及大而惊人的崩溃。

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

  

在我看来,如果你不想修改变量,就不要这样做。

嗯,这一切都很好,但没有人是完美的。程序员犯错误。这允许编译器 - 从不犯错误(至少通常不会) - 指出它们。

当您使用某些数据变量时,它会特别有用,它可以创建许多代码行。它越远,就越容易修改它而不会意识到你不应该这样做。对于大型复杂的代码库,它只是必须的。

您在代码库中获得了可证明性正确性稳定性的新衡量标准,以及可能的原因非常微妙和令人讨厌的错误。当编译器知道某些值在编译后不会改变时,编译器(在某些情况下)还有很多优化机会

我们可以整天列出优势,但实际上,在你使用这样的代码库之前,你不会完全 grok

事实上,在一个完美的世界中,所有变量默认为const ,您需要使用关键字mutable来声明它们能够改变它们。 C ++是向后的。

答案 1 :(得分:40)

至少在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 tells the compiler about thread safety

现在,毫无疑问,您可以定义一些其他语言(在其他方面)与C或C ++有某些相似之处,而这些语言在这些方面没有使用const。结果将是与任何一种语言截然不同的语言。在不知道你的意图的情况下,不可能说它会如何发展,但最终可能会更接近Java或C#(有几个例子),这两者在某些方面都与C和C ++有些相似,但不是这个特别的一个(即,不要像C和C ++一样使用const)。

答案 2 :(得分:36)

除了在其他答案中已经讨论过的通常的编程注意事项,我关注的一点是态度:

  

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

一般的经验法则是,编写代码的成本的20%用于开发阶段。另外80%是在代码的生命周期内进行升级,维护它等等。这意味着除了你自己以外,很多其他人都会使用你的代码。

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

另外,@ worlboss,我听到了相当多的不宽容。正如其他一些人所评论的那样,碳单位会犯错误,硅单位可以采取任何措施来帮助避免错误。

答案 3 :(得分:21)

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

答案 4 :(得分:17)

有两个原因:

  1. 编译器强制文档
  2. 编译器优化
  3. 来自Ian Lance Taylor(曾在gccgold链接器上工作过)的好explanation

      

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

         

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

答案 5 :(得分:6)

这是一个简单的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 - 强制保存到要传递给函数的数据中。因此,在这种情况下,我可以合理地确定比较两个列表不是在我进行运行时调试时将它们修改的函数,因为我保护自己免受意外修改我的数据。 ;)

答案 6 :(得分:5)

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

示例:你有a和b,你想要添加它们,你做a + b。如果你声明a是const且值为3,那么程序将改为3 + b,这将节省内存和周期,因为它不需要检索一个值。

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

答案 7 :(得分:4)

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

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

谈论评论,当截止日期即将来临,并且有很多东西仍然没有工作时,对每个功能的评论都只是浪费时间。但是在某些情况下,评论是必须的,因为第一个问题(截止日期)可能无法阅读评论,因为大多数评论都没用,但重要的评论也会被忽略。因此,最好使用const关键字,这会产生编译错误并指出问题,然后编写和阅读大量注释。

答案 8 :(得分:2)

这是一个难题,因为IMO基于信仰。其中一个信念是,只需添加更多代码,您就可以保护代码免受某些更改。当然,编译器使用额外的代码来检查一切是否正常。

我认为这并不总是正确的,你不能保护你的代码免受你自己或你的开发团队只是添加关键字,事实上有很多语言没有任何const,public,private,protected,internal,int ,浮动,双重关键词,这并不意味着它们不是好语言。

一些代码模式也是如此,人们为什么浪费这么多时间来讨论单身人士呢?如果你只想拥有一个实例,你唯一要做的就是只创建一个实例,就是这样。周围到处都是同样的心态,看看10年前发布的防御性编程文章,再一次用代码保护代码的想法。

在某些时候,您必须决定在开发人员手中或编制者手中设置职责的位置。但是,编译器和任何其他工具都无法针对开发人员保存代码,因此许多关键字毫无价值,或者只是与其他开发人员进行通信的方式。

答案 9 :(得分:1)

常量变量只允许您编写更易读的代码。

几乎所有语言中const的最大用处是允许我们使用名称来引用常量值,因此您可以使用流利的语言告诉其他人这个名称所引用的内容,而无需传播注释在您的代码中,节省读者的时间和精力,以了解参数的参数类型和特性。当然,如果在代码中重复使用常量值,您也会受益。好吧,像这样的代码可以更具可读性:

processPages(LETTER_PAPER_WIDTH, LETTER_PAPER_HEIGHT);

......比这个:

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

在上面的示例中,您需要了解每个参数是什么,它的单位和解释值的类型,还需要根据注释验证它,因为像这样的冗余注释(那些重放什么的注释)编码)不是一个可靠和有用的评论(罗伯特马丁在清洁代码中的错误评论:http://goo.gl/5EyY)。

答案 10 :(得分:-2)

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

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