71

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

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

4

11 回答 11

101

除了向代码的读者说明,如果您修改此变量可能会导致错误(您可以使用注释来执行此操作)

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

  • C++ 编译器将通过编译失败和诊断消息(“编译器错误”)强制执行它,无需注释;
  • AC 编译器将在大多数情况下强制执行它,尽管它的标准库由于遗留问题而存在漏洞,例如strchr,并且它具有一些相当宽松的隐式转换规则,可以让您在const不很容易意识到的情况下放弃它。但是,编译成功并不意味着没有错误。不幸的是,这确实意味着错误可能是程序中的细微错误,也可能是大而壮观的崩溃。

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

在我看来,如果您不想修改变量,那就不要了。

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

当您在远离创建位置的地方使用很多很多行代码时,它特别有用。它越远,修改它就越容易,而不会意识到你不应该这样做。对于大型、复杂的代码库,这是必须的。

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

我们可以整天列出优势,但实际上,在您使用过这样的代码库之前,您不会完全理解它。

事实上,在一个完美的世界中,所有变量都是constdefault,您需要使用关键字声明它们mutable才能更改它们。C++ 是倒退的。

于 2013-08-10T00:41:31.963 回答
42

至少在 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++ 有点相似,但不是这个特别的一个(即,不要const像 C 和 C++ 那样使用)。

于 2013-08-10T00:52:13.253 回答
38

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

在我看来,如果您不想修改变量,那就不要了。

一般的经验法则是,编写代码的 20% 的成本都花在了开发阶段。剩下的 80% 用于代码的整个生命周期中对其进行升级、维护等。这意味着除了您自己之外,还有许多其他人将处理您的代码。

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

另外,@worlboss,我听到了相当多的不容忍。正如其他一些人所评论的那样,碳单元会犯错误,而硅单元可以做的任何事情来帮助避免错误都是值得赞赏的。

于 2013-08-10T01:29:25.503 回答
21

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

于 2013-08-10T00:39:33.710 回答
17

两个原因:

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

这是来自 Ian Lance Taylor(他从事链接工作)的一个很好的解释gccgold

const 的第一个含义对程序有真正的影响。声明为 const 的变量的编译方式可能与未声明为 const 的变量不同。

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

于 2013-08-10T00:59:05.327 回答
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您传递给函数的数据强制执行的指针的-ness。因此,在这种情况下,我可以合理地确定比较两个列表并不是在我进行运行时调试时破坏它们的函数,因为我已经保护自己免受意外修改数据的影响。;)

于 2013-08-10T12:25:12.743 回答
5

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

例如:你有 a 和 b,你想添加它们,你做 a + b。如果您将 a 声明为 const 且值为 3,则程序将改为 3 + b,这将节省内存和循环,因为它不需要检索 a 值。

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

于 2013-08-10T10:05:49.043 回答
4

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

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

谈论评论,当最后期限即将到来并且有很多东西仍然无法对每个功能进行评论时,这只是浪费时间。但是在某些情况下,评论是必须的,因为第一个问题(截止日期)评论可能不会被阅读,因为大多数评论是无用的,但重要的评论也会被跳过。所以最好使用const给出编译错误并指出问题的关键字,然后编写和阅读大量评论。

于 2013-08-12T12:30:07.013 回答
3

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

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

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

在某些时候,您必须决定在哪里设置职责,在开发人员的手中或在编译器的手中。但是,无论是编译器还是任何其他工具都不能保存代码以对抗开发人员,因此许多关键字毫无价值,或者只是与其他开发人员交流的一种方式。

于 2013-08-14T01:32:45.003 回答
1

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

几乎所有语言中最常用的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)。

于 2013-08-13T21:08:39.180 回答
-2

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

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

于 2013-08-10T05:51:58.327 回答