0

我试图弄清楚在编写 C++ 代码时何时应该使用 const 。这些都是悲观的例子还是以这种方式编写代码有益?:

示例 1:

int findVal(const int OTHER_VAL) const
{
    switch(OTHER_VAL)
    {
    case 1:
        return 2;
    default:
        return 3;
    }
}

示例 2:

enum class MobType
{
    COW, CHICKEN, DOG, PIG
};

class BaseMob
{
protected:
    BaseMob(const MobType TYPE) : TYPE(TYPE) { }

    const MobType TYPE;
};

示例 3:

void showWorld(const World &world)
{
    auto data = world.getData();
    for (auto &i:data)
        i.print();
}
4

2 回答 2

3

不,他们不是。

const具有自动存储功能的局部变量(包括函数 args)是纯粹的语法糖,可帮助人类程序员为其代码设置规则。它根本没有帮助优化器。优化编译器从 C 源代码中提取必要的数据移动,并对其进行优化。他们通常不在乎您是否将相同的 tmp 变量用于许多不同的事物,或者const tmp1 = a+10;在同一函数中有 10 个不同的变量。

是的,这适用于按值传递的函数 args;它们是具有自动存储功能的局部变量,在寄存器或堆栈中传递。不,这并不意味着调用者可以假设一个函数没有修改用于参数传递的堆栈内存,因此它对优化器也没有多大帮助。(使用相同的参数进行第二次函数调用仍然需要将 args 重新写入堆栈(如果不是所有 args 都适合寄存器),因为conston arg 不会改变被调用函数“拥有”该堆栈的事实空间,并且可以根据需要将其用作暂存空间。)


const静态/全局/参考变量确实有帮助。 static const int foo = 10;可以内联为立即常量,而不是从内存中加载。(例如add eax, 10,代替add eax, [foo])。


使用const将类方法标记为不更改任何类成员也可以帮助编译器避免在函数调用后重新加载类成员。(即让他们住在寄存器中)。这主要只适用于编译器看不到函数定义的情况,否则一个好的优化编译器可以只查看被调用函数的作用并进行相应的优化。(只要它不在 Unix 库中,符号插入意味着它不能假定它在编译时看到的被调用函数将是动态链接后调用的函数。)

于 2016-06-09T20:53:36.517 回答
3

每当您在逻辑上不更改值或对象时,您都应该进行更改const。从逻辑上讲,我并不是指每次在技术上都允许这样做,而是每次在函数、类和代码的上下文中都是合乎逻辑的。

一个简单的示例可以是示例 1 中所示的简单“get”函数,这些函数不应修改类的状态,因此应标记为常量,因为这将有助于向用户记录您的意图,同时帮助您确保类的不变性。

在某些情况下,创建不可变对象是有意义的,如示例 2 所示。我们在 C++ 中并不经常看到这些,但许多其他语言经常使用它们。如果它没有添加任何值以能够在对象生命周期内更改某个成员,那么您不妨将其设为 const。

传递 const 引用参数可以为您提供引用的性能优势,但同时确保源对象保持不变,这对用户来说既是很好的文档,也允许进行 som 优化。

提到了所有这些原因,还有其他原因可以使用const,如上一段中简要提到的,优化。当编译器知道某些东西是不变的并且没有被改变时,它可以启用一些非常聪明的优化,但不要const出于性能原因使用。

这也是为什么通过(例如)const_cast可以抛弃的演员来解决 constnessconst会导致一些不良行为的原因。例如,检查以下内容:

#include <stdio.h>

static const int foo = 10;

int constsum(void) {
  return foo + 5;
}

int main(int argc, char* argv[]) {
  int a = constsum();
  int* newFoo = const_cast<int*>(&foo);
  *newFoo = 20;
  int b = constsum();
  printf("%d\n", a + b);
  return 0;
}

从这个例子中可以看出(见这里运行的代码),这可能不会产生预期的结果,因为代码会30被打印出来,而不是预期的 40。

在检查生成的程序集时,我们可以看到原因(编译成程序集):

constsum():
        mov     eax, 15
        ret
main:
        mov     eax, 30
        ret

编译器只是内联值,因为它可以看到它们是常量,它并不特别注意const_cast正在使用的值。

所以 const 正确性和使用const是一个有价值的工具,它可以提高代码的性能和稳定性,而且(不要忘记)它有助于记录你的代码。

于 2016-06-09T20:58:10.043 回答