在C / C ++中,应尽可能在参数和局部变量中使用'const'吗?


13

这个问题的灵感来自java中的一个问题final

在C / C ++中,应const尽可能使用?

我知道已经有一个关于const在参数中使用的相关问题。不幸的是,这个问题及其答案不能完全回答我的问题,因为它仅与函数参数有关,但我也想了解其他情况(例如:局部变量)。

另外,几乎所有该问题的答案都说我们应该使用,const因为它包含有关变量可访问性的有用信息。但这似乎与在Java使用final的答案相抵触,因为final如果其中不包含额外的信息,状态可能是多余的,因此应省略它以使代码简洁明了。

那么,我应该const尽可能使用吗?如果是这样,为什么constC ++中的建议final与Java中的建议不同?

Answers:


18

首先,由于您引用了Java final,因此与完全不同const。Final表示引用不能更改,但对可变性没有任何说明。const进一步说“ const引用不能变异”,这是一个更有力的保证。为此,在Java中,内部状态必须是最终状态,并在构造时确定。const易于使用,并且可以将现有对象“提升”为const引用。

是的,您应该尽可能使用const。它与您的代码保持不变,这是一个约定。请记住,可以将非常量变量传递给接受const参数的函数。您总是可以添加const,但不能删除它(不是没有const cast,这是一个非常糟糕的主意)。

常数正确性有时可能很乏味,但有助于保证不变性。这在线程共享对象的多线程代码中至关重要。它使某些任务更加有效:无需复制状态,而只需重用相同的不可变对象。库可能会接受const参数,以便向程序员提供保证,不会,您的对象不会在库的胆怯的黑洞中以不可预测的方式更改。


1
投上赞成票,因为您解释了这一点finalconst但没有相同的保证。
比尔·

2
稳定性与可写性有关,而不与可变性有关。
Basilevs

@Basilevs如果写入对象会发生什么?它会变异。您如何突变对象?写给它。

4
如果您写入const引用会怎样?编译时错误。如果您通过另一个非const引用写入由const引用所引用的对象,会发生什么情况?它会变异。不可变的对象不能突变,因此const引用不一定引用不可变的对象。
Basilevs

@Basilevs您的观察仅适用于const refs。如果对象本身被声明为const(而不仅仅是引用),则它或多或少是不可变的(除非有人邪恶地抛弃了constness)。
马修·詹姆斯·布里格斯

4

就个人而言,const花费的时间很少,而读取的时间却很少,通常比检查任何代码是否使变量突变所需的时间少得多,这实际上阻止了我编写错误(有人偶然增加了其最终迭代器吗?等等)

我还发现对const使用的严格要求会以其他方式引导我朝着更好的代码发展,例如创建辅助函数来进行非平凡的初始化。


4

我将不同意其他海报,建议您不要const在局部变量和参数上使用顶级。(指向const的引用和指针,即const T&,是不同的,您应该在适当的时候始终使用它们来确保正确性。)

顶级的优点const是:

  • 明确表明局部变量不是要突变的。
  • 如果您不小心尝试对其进行突变,则会给出编译器错误。

缺点是:

  • 视觉混乱。
  • 不能在“伪常量”变量上使用,即以某种方式初始化的变量比直接构造更复杂,但是之后不能修改,例如使用getline

    std::string line; // cannot be const
    std::getline(std::cin, line);
    // line should be const from here on out
  • 防止在函数调用和返回时进行移出优化:

    std::string f1();
    std::string f2(std::string s);
    std::string f3() {
      const std::string s = f1(); // s is not meant to be modified
      // but I still want the move optimization here:
      const std::string result = f2(std::move(s)); // this doesn't move
      // and I want the compiler to move out here:
      return result; // this will probably RVO, but if not, the move
                     // constructor will not be used due to the const
    }

我在一个const使用了local的代码库中工作,但我发现它根本没有帮助,但是如上所述,它在代码中却充满了微妙的悲观感。我个人更喜欢采用一种通用策略,即尽可能少地修改变量,并且使函数足够小以使变量的使用显而易见,并且即使对其进行了修改,函数的复杂度也很低,以致于无法使用。 -问题。


2
关于搬迁的要点是显示您不打算以常量方式使用本地,因为您(打算)通过搬迁进行修改
Caleth,2016年

1
@Caleth不,这就是重点。我无意修改它。我只想传递值或返回它,并且我希望它高效。从概念上讲,修改只是一种优化,并不意味着可以观察到(因为之后没有使用变量)。实际上,是的,需要进行修改,因为C ++没有真正的破坏性移动(如Rust那样)。这就是我不希望const在本地用户上使用的原因:因为它阻止了技术修改,而不仅仅是概念上的修改。
塞巴斯蒂安·雷德尔

2
您不想修改,但您确实想修改变量。您可以改用const&,也可以不修改它们
Caleth

2

const关键字应该用于局部变量,就像参数。之所以有用,是因为:

  • 更容易阅读代码。当有人读取变量声明时,她知道它不会更改。阅读代码时要少担心的一件事。
  • 防止您意外修改变量
  • 没有运行时间的损失,所有内容都是静态检查的。这就像免费午餐,const只需要花一秒钟的时间写,所以没什么大不了的。
  • 在多线程应用程序中创建变量/参数始终是一个好主意。即使您的应用程序不是多线程的,它仍然是一个好习惯。
  • 您为C ++编译器提供了优化代码的机会。

请注意,这里没有正确/错误的答案。在您的链接中,投票最多的答辩者认为final不应在本地使用。但是,下一个回答者强烈推荐它。

如果您的函数既简单琐碎,则不要添加,const因为每个人都可以理解您的意图。但是,如果函数中的逻辑不平凡,则应使用关键字。记住,几乎没有损失。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.