【问题标题】:Making a char function parameter const?制作一个char函数参数const?
【发布时间】:2010-12-21 13:49:38
【问题描述】:

考虑这个函数声明:

int IndexOf(const char *, char);

其中 char * 是字符串,char 是要在字符串中查找的字符(如果未找到 char,则返回 -1,否则返回其位置)。将字符也设为const 是否有意义?我总是尝试在指针参数上使用 const,但是当按值调用某些东西时,我通常不使用 const。

你有什么想法?

【问题讨论】:

  • 为什么是近距离投票?对我来说似乎是一个有效的问题。
  • 如您所见,这更像是一个宗教问题。之前也有人问过。可以提出支持或反对任何一方的论点。我建议你阅读我上面提供的链接,然后自己决定。
  • @John Dibling:另一个问题实际上是关于提出论点const。这只是有点混乱,请参阅“使字符也const”引用:它假定第一个参数已经是const。不是,但它指向的字符串是。
  • @MSlaters:我没有看到区别?通过我的阅读,这个问题似乎提出了完全相同的问题。

标签: c++ c


【解决方案1】:

假设您不打算调整任一参数的值:

我将函数定义为:

int IndexOf( const char * const , const char )
{
    //...
}

但保持函数声明为:

int IndexOf( const char * , char );

换句话说:
我会在标题中显示const最低 级别,然后在实施中使用const最大可能 级别。

为什么?

  1. 分离标头和实施允许我更改实施中const 的参数而无需接触标头(除了那些至关重要的const应该需要更改标头)。
  2. 它使代码更具自我记录性。
  3. 如果没有编译器将它们作为错误捕获,就更难引入错误。
  4. 这使得其他程序员在将来进行更改时更难引入错误。

设置传递值参数const 与否在影响函数调用者方面“没有影响”——这就是为什么你应该将它们排除在标题之外——但它们可以使你的实现更加健壮并且更易于维护。

显然,如果更改参数比将其复制到另一个局部变量更有用,那么不要为了这样做而将其设为const

【讨论】:

  • 实际上,这是未定义的行为;见 C99 6.5.2.2 §9(或 6.7 §4)、6.7.5.3 §15、6.7.3 §9
  • 您的答案对于 C++ 是正确的。顶级常量在函数声明中被忽略。例如, void f(int);与 void f(const int); 相同。当然,常量指针或常量引用不被视为顶级。强烈建议在函数声明中省略顶级 const。
【解决方案2】:

与我的共同回答者相反,我会使用 char const。毕竟,您不想在搜索过程中更改要查找的角色,对吗?并且由于这样做无意中很可能会弄乱您的算法,const 有助于使您的代码健壮且易于维护。

【讨论】:

    【解决方案3】:

    这没有意义,因为如果你修改第二个参数的值,调用者不会受到影响。

    此外,如果您需要在函数内部修改此参数,它可能会帮助您在堆栈上节省一些字节,而不必声明单独的局部变量。

    下面的代码是修改参数而不是局部变量的一个很好的例子:

    void foo (int count) {
      while (count--) {
        do_something();
      }
    }
    

    但是,如果您的函数较长并且您不打算修改其参数,则将相应的参数标记为const 可能在维护方面是有益的,但仅限于其定义,不在位于头文件中的声明中。如果您后来决定某个参数不应该是 const,您只需在定义中更改它。

    【讨论】:

    • 同意,我倾向于删除这些没有意义且可能会混淆的常量。
    • 不同意:当然不会影响调用者,但影响维护程序员。想象foo 有五个屏幕长,而您在某处需要count 的值。您必须解析整个函数以查看是否有人在某处对其进行了修改。如果您像这样删除 const 关键字,则必须对更改函数时使用的每个参数执行此操作。如果您不打算更改参数,最好将其标记为 const。
    • @nikie:当你说foo 有五个屏幕长时,你的论点不再令人信服。问题不在于参数不是 const,而在于您有一个五页长的函数。重构你的代码,双赢。
    • @GMan:五个屏幕可能被夸大了,真的。但是一个中等复杂的算法的实现很容易有一百行或更长,没有很多重构的机会。例如,查看 FLANN、libsvm、boost 或 FFTW 的源代码。
    • @nikie:其中我对 Boost 很熟悉,但我不知道很多长函数。
    【解决方案4】:

    对于您给出的答案的示例是有道理的,但在更一般的按值传递的情况下,const 可能会有所帮助。

    通常这可能适用于非 POD 类型,即使按值传递也不能保证更改不会产生可见的副作用。此外,如果您绝对知道您的实现不会想要更改它,则标记它const 可以帮助编译器在以后有人意外更改值时发现错误。

    我倾向于遵守规则“标记它const,除非有理由不使用const

    【讨论】:

      【解决方案5】:

      我认为没有必要,因为 char 的值将被复制,并且对它的任何更改都不会反映在其范围之外。

      【讨论】:

        【解决方案6】:

        没关系,只要你是一致的

        如您所见,这个问题是一个宗教问题。人们站在任何一方,往往强烈反对对方。

        可以支持或反对任何一方。所提出的论点可能相互矛盾。

        例如,“make it const”阵营中的论点倾向于认为,对于从事该功能的维护程序员来说,它使代码更具自我记录性。这很可能是真的,您可能认为这是将您的按值参数标记为 const 的充分理由。然而,这枚硬币的另一面是,您可能决定有一天您确实需要修改函数中的变量,这将需要您更改签名或制作本地副本。此外,作为 const 的标记确实为维护程序员添加了一些文档,它还为客户端程序员添加了文档——但该文档充其量是误导性的。它向调用者暗示了某些不存在的语义。

        但无论你做什么,你都需要坚持不懈。要么将所有按值参数设置为 const,要么不设置。前后不一会破坏您通过采取任何一方而获得的任何文件利益。

        【讨论】:

          【解决方案7】:

          如果是 3 行函数,const 没有多大帮助。

          但如果你必须了解和维护一个 300 行的函数,那么在使用它的第 289 行之前不会更改局部变量或参数可能是一个非常重要的线索。

          【讨论】:

            【解决方案8】:

            专业人士const:

            • 防止参数在被调用者中被意外修改

            反对const

            • 在不向调用者提供有用信息的情况下添加混乱
            • 实现更改(即删除限定符)将更改接口

            理想的解决方案是仅在作为函数定义一部分的声明中提供const。但是,C 标准不允许这样做;不过,它会在 C 语言的所有合理实现中按预期工作。

            【讨论】:

              【解决方案9】:

              我会说const 绝对不会在您的代码中添加任何内容。

              【讨论】:

              • 如果函数内部的参数没有改变,它应该是const
              • @Pawel:是的,但这不是调用者关心的事情,它更多的是内部实现问题。
              • @Blagovest:如果可以是conts,它应该是const。这就是我的看法。但你是对的,这并没有改变什么——只是一个良好的编码风格 IMO 的问题。
              • @Pawel:按照这个逻辑,大多数函数都会采用 const 参数。对函数作用的影响为零,因此 IMO 可以并且应该省略它。
              • @mingos: const 从不向您的代码添加任何内容。它对函数的作用没有任何影响。它只会告诉编译器(以及下一个修改您的代码的程序员)您打算更改本地或参数。 (恕我直言 const 应该是默认值并且应该标记可变值,但这是另一个讨论。)
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-09-22
              • 2013-12-20
              • 2012-02-27
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多