C ++ const关键字 - 大量使用?

时间:2009-10-12 13:59:46

标签: c++ syntax const

在以下C ++函数中:

void MyFunction(int age, House &purchased_house)
{
    ...
}


void MyFunction(const int age, House &purchased_house)
{
    ...
}

哪个更好?

在两者中,'age'按值传递。我想知道'const'关键字是否有必要:对我来说似乎是多余的,但也很有用(作为额外的指示,变量不会改变)。

有没有人对上述哪种(如果有的话)更好有任何意见?

12 个答案:

答案 0 :(得分:63)

首先,它只是一个实现细节,如果你把 const 放在那里,不要把它放在声明集(标题)中。只将它放在实现文件中:

// header
void MyFunction(int age, House &purchased_house);

// .cpp file
void MyFunction(const int age, House &purchased_house);
{
    ...
}

定义中的参数是否为const纯粹是一个实现细节,不应该是接口的一部分。

我经常没见过这种事情,我也不这样做。拥有参数const会让我更加困惑而不是帮助,因为我会立即将模式匹配 - 将其失败为“const int& age”:)这当然与使用 const 完全不同另一个层面:

// const is a *good* thing here, and should not be removed,
// and it is part of the interface
void MyFunction(const string &name, House &purchased_house);
{
    ...
}

在这种情况下,const将影响函数是否可以更改调用者的参数。应尽可能经常使用此意义的Const,因为它可以帮助确保程序的正确性并改进代码的自我记录。

答案 1 :(得分:41)

我建议阅读Herb Sutter. Exceptional C++。有一章“Const-Correctness”。

  

“实际上,对于编译器,无论是否在值参数前面包含此const,函数签名都是相同的。”

这意味着这个签名

void print(int number);

实际上与此相同:

void print(int const number);

因此,对于编译器,声明函数的方式没有区别。并且你不能通过将const关键字放在pass参数值前面来重载它。

进一步阅读,Herb Sutter建议:

  

“避免在函数声明中使用const pass-by-value参数。如果不修改参数const仍然在同一函数的定义中。”

他建议避免这个:

void print(int const number);

因为这个const令人困惑,冗长和多余。

但是在定义中,你应该这样做(如果你不改变参数):

void print(int const number)
{
   // I don't want to change the number accidentally here
   ...
}

所以,你会确定即使在1000行函数的主体之后你总是没有触及数字。编译器将禁止您将该数字作为非const引用传递给另一个函数。

答案 2 :(得分:23)

这是恕我直言,过度使用。 当你说'const int age,...'时你实际上说的是“你甚至不能改变你职能中的本地副本”。你所做的实际上是通过强迫他使用另一个本地副本,当他想要改变年龄/通过非const引用传递它时,使程序员代码的可读性降低。

任何程序员都应该熟悉传递引用和传递值之间的区别,正如任何程序员应该理解'const'一样。

答案 3 :(得分:9)

您不仅表示它不会改变,它将阻止您的代码认为它可以并且它将在编译时被捕获。

答案 4 :(得分:8)

请参阅Meyers和'Effective C ++',并使用const自由,特别是使用pass-by-reference语义。

在这种原子变量的情况下,效率并不重要,但代码清晰度仍然有益。

答案 5 :(得分:7)

好吧,正如其他人已经说过的那样,从C ++语言的角度来看,上面的const对函数签名没有影响,即函数类型保持不变,无论const是什么有没有。它在抽象C ++语言层面的唯一影响是你不能在函数体内修改这个参数。

但是,在较低级别,应用于参数值的const修饰符可以具有一些优化优势,给定足够聪明的编译器。考虑具有相同参数集的两个函数(为简单起见)

int foo(const int a, const double b, const long c) {
   /* whatever */
}

void bar(const int a, const double b, const long c) {
   /* whatever */
}

让我们说代码中的某处,如下所示

foo(x, d, m);
bar(x, d, m);

通常,编译器在调用函数之前使用参数准备堆栈帧。在这种情况下,堆栈通常会准备两次:每次调用一次。但是聪明的编译器可能会意识到,由于这些函数不会更改其本地参数值(使用const声明),因此为第一次调用准备的参数集可以安全地重用于第二次调用。因此它只能准备一次堆栈。

这是一个相当罕见且模糊的优化,只有在调用点(相同的转换单元或高级全局优化编译器)知道函数的定义时才能工作,但有时它可能是值得一提。

说它“毫无价值”或“没有效果”是不正确的,即使使用典型的编译器也可能是这种情况。

值得一提的另一个考虑因素是性质不同。那里有编码标准,要求编码人员不要改变初始参数值,如“不要将参数用作普通局部变量,参数值应在整个函数中保持不变”。这有点意义,因为有时它可以更容易地确定函数最初给出的参数值(在调试器中,在函数体内)。为了帮助实施此编码标准,人们可能会在参数值上使用const说明符。值得与否是一个不同的问题......

答案 6 :(得分:4)

使用const的一个好处是,您不会在age的中间意外更改MyFunction的值(如果您忘记它没有通过引用传递)。一个“缺点”是您无法使用age等代码回收foo.process(++age);

答案 7 :(得分:4)

你是对的,“const int age”的唯一目的是年龄不能改变。然而,对于大多数程序员来说,这可能是非常混乱的。因此,如果这些方法在代码中没有被广泛使用,我建议省略const。

答案 8 :(得分:4)

第二种变体更好。在第一个中你可以意外地改变变量年龄。

答案 9 :(得分:4)

如果(并且仅当)您将在任何其他不会被修改的局部变量上使用它,您应该对参数使用const

const int age_last_year = age - YEAR;

在可能的情况下标记局部变量const有时很方便,因为这意味着您可以查看声明并知道该值,而无需考虑中间代码。您可以在将来轻松更改它(并确保您没有破坏函数中的代码,如果它现在代表稍微不同的变量,可能会更改变量的名称,这是可更改的,而不是之前的不变的东西)。

与此相反,它确实使代码更加冗长,而在一个简短的函数中,几乎总是非常明显的是哪些变量发生了变化,哪些变量没有变化。

所以,要么:

void MyFunction(const int age, House &purchased_house)
{
    const int age_last_year = age - YEAR;
}

或:

void MyFunction(int age, House &purchased_house)
{
    int age_last_year = age - YEAR;
}

答案 10 :(得分:4)

以下是一些很棒的文章和一本书,我发现了解释使用const的优点:


我可以向您提出以下格言吗?

如果一个对象/变量可以被限定为常量,那么它应该是。在最坏的情况下,它不会花费任何成本。最好的情况是,您将在代码中记录对象/变量的角色,这将使编译器能够更好地优化您的代码。

有些编译器忽略了使用'const'来利用优化的潜力,这导致许多专家在可以使用时忽略了按值使用常量参数。这种做法要求更严格,但不会有害。在最坏的情况下,你不会失去任何东西,但是你也没有获得任何东西,最好的是,你从这种方法中获胜。


对于那些似乎不了解const在函数/方法的by参数中的效用的人......这里有一个简短的例子来解释原因:

的.cpp

void WriteSequence(int const *, const int);

int main()
{
    int Array[] = { 2, 3, 4, 10, 12 };
    WriteSequence(Array, 5);
}


#include <iostream>
using std::cout;
using std::endl;
void WriteSequence(int const *Array, const int MAX)
{
    for (int const * i = Array; i != Array + MAX; ++i)
      cout << *i << endl;
}

如果我在int MAX前面删除了const并且我在这里写了MAX + 1会怎么样?

void WriteSequence(int Array[], int MAX)
{
    MAX += MAX;
    for (int * i = Array; i != Array + MAX; ++i)
      cout << *i << endl;
}

你的程序会崩溃!现在,为什么会有人写“MAX + = MAX;” ?也许人为错误,也许程序员当天感觉不舒服,或者程序员根本不知道如何编写C / C ++代码。如果你有const,代码甚至都没有编译!

安全代码是一个很好的代码,当你拥有它时,不需要花费任何东西来添加“const”!


以下是针对一个非常相似问题的不同帖子的答案:

  

“const在论证时毫无意义   因为你不会通过值传递   修改调用者的对象。“

     

错误。

     

这是关于自我记录代码的   和你的假设。

     

如果您的代码有很多人在工作   它和你的功能   非平凡,那么你应该标记   “const”任何和你的一切   能够。在写工业实力的时候   代码,你应该总是假设   你的同事是精神病患者   以任何方式帮助你   (特别是因为它经常是你自己   在将来)。

     

此外,正如有人提到的那样   之前,它可能有助于编译器   稍微优化一下(尽管它是一个   远射)。

以下是链接:answer

答案 11 :(得分:1)

具有通过值const传递的基本类型几乎毫无价值。将const传递给函数通常可以作为与调用者的契约,即函数不会更改该值。在这种情况下,因为int是按值传递的,所以函数不能进行任何在函数外部可见的更改。

另一方面,如果不对对象进行任何更改,则rreferences和非平凡对象类型应始终使用const。从理论上讲,这可能会带来一些优化,但最重要的是我上面提到的合同。缺点当然是,它可以使您的界面更大,并且改进现有系统(或使用不使用const的第三方API)是一件困难的事情。