【问题标题】:Benefits of using "const" with scalar type? (e.g. "const double" or "const int")将“const”与标量类型一起使用的好处? (例如“const double”或“const int”)
【发布时间】:2012-01-14 11:13:08
【问题描述】:
///////////////////////////////////////
class A {
    ...
    const double funA(void)
    {...}
};

A a;
double x = a.funA(); 
// although the intention is to
// enforce the return value to be const and cannot be
// modified, it has little effect in the real world.

class A2 {
    ...
    double funB(void)
    {...}
};

///////////////////////////////////////
class A {
    void setA(const double d)
    { // now you cannot change the value of d, so what?
      // From my point of view, it is NOT a good practice to change the pass-in parameter
      // in this case, unless you want the caller to receive that change
      // instead, you can do 
      // const double dPassIn = d;
      / /then use dPassIn instead.
      ...
    }
};

class A2 {
    void setB(double d)
    {...}
};

//////////////////////////////////////

根据我的理解,我们应该更喜欢 使用 A2::funBA2::setB 因为 constA::funAA::setA 都没什么意义。

// 更新 //

    FMOD_RESULT F_API EventSystem::getReverbPresetByIndex(const int index, 
                                FMOD_REVERB_PROPERTIES *props, char **name = 0);

我认为 FMOD 是一个精心设计的包,它确实在函数参数列表中使用了const int。 现在,我同意A::setA(const double d) 有它的优势。

【问题讨论】:

  • 您说最好保持参数不变“...除非您希望调用者接收该更改...”。在这种特殊情况下,调用者不会收到更改,因为参数是按值传递的。您需要传递一个引用/指针。

标签: c++


【解决方案1】:

当按值返回时,常量不起作用,因为它无论如何都不能强制执行。一些编译器会发出警告。然而,返回一个指向常量数据的指针/引用是有意义的。

将参数传递给函数时,最好(更安全,允许编译器优化)将其作为常量传递,除非您绝对需要更改数据。

【讨论】:

  • 但是它确实限制了您可以在函数中使用的算法 - 不会对输入进行不必要的复制。您不希望因为函数侧的算法更改而不得不更改函数的定义。
  • @Martin Beckett 有些人喜欢制作副本,因为它可以保持输入(初始值)不变......
  • 我会对你的回答做一个非常非常小的修改。如果按值返回对象,将其设为 const 会阻止用户对该值调用非 const 方法。显然,用户总是可以将返回的值分配给一个非常量值并在那里调用该方法。 ;) 这几乎是我能想到的。我认为 if const 会阻止您执行“if( foo() = 42 )”,但结果编译器实际上捕获了该错误,因为返回不是左值。
  • @fronsacqc :按值返回 const 对象也会抑制移动语义,这绝不是一件好事。此外,允许在临时对象上调用非常量成员函数可能是一件好事,甚至是惯用的——参见例如C++03 std::vector<>shrink-to-fit 成语。
  • @MartinBeckett:添加或删除顶级 const 限定符并不意味着更改函数的声明。不要将这些 const 放在头文件中(它们对调用者没有意义),在实现文件中随心所欲。
【解决方案2】:

const 关键字告诉编译器“在我的函数 setB 中,我不会更改参数。如果您想针对多线程进行优化,您可以在另一个上下文中同时使用此变量,因为我的工作不会更改它。”

所以我想说,在编程逻辑中,第二个变体更好,就像你说它“意义不大”,但在更广泛的逻辑中,如果你看到真正发生的事情,你应该声明 const,什么是 const,并且不要声明 const 什么不是 const。它是一种编译器可以理解的文档,可能会用来优化您的代码!

【讨论】:

  • 我更新了我的 OP。我仍然认为在这种情况下修改传入的 double 参数不是一个好习惯,也不应该通过在函数参数列表中冗余使用 const double 来强制执行。
  • 不正确。听说过 const_cast 吗? const 是为了防止你犯错误并修改你不应该修改的东西,句号。
  • @q0987 :如果这是不好的做法,那么如何强制防止这种不好的做法是多余的?
  • @q0987 有人推荐这种做法,但当然,你为复制付费...
  • 在更复杂的函数的情况下,最好保持初始值不变,以防以后需要它们。在非常简单的函数(热点)的情况下,使用参数数据可能是可以接受的。
【解决方案3】:

在我看来,更改传入参数不是一个好习惯

然后通过在函数定义中的参数上使用const 来声明它是有意义的。并非每个人都遵循这种做法,因此对于您的代码的未来读者来说,在参数上添加 const 比扫描整个函数体以修改参数更好。

即使您遵循实践,也很容易错误地修改变量(= 的经典错字而不是 == 或通过非常量 ref 或指针传递 arg)。实现中的 const 参数可以防止这种情况发生。

另一方面,声明中的const int 参数(如果与定义分开)没有意义。

【讨论】:

    【解决方案4】:

    在实践中,标量并没有真正的好处。

    但是,理论上它可以帮助编译器执行额外的优化,例如传递对常量的引用而不是复制双精度值。

    【讨论】:

    • 我认为在这种特殊情况下它不会保存任何通过引用传递的东西。在更广泛的对象(例如字符串等)的情况下当然更可取...
    • 当然,但不要忘记双精度浮点使用 FPU 寄存器,而不是用于指针和引用的传统寄存器。编译器可能会使用该技巧来减少 FPU 负载。
    猜你喜欢
    • 2013-10-15
    • 2010-11-02
    • 2015-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-11
    相关资源
    最近更新 更多