繁体   English   中英

C ++-const参数和类变量是否被简化?

[英]C++ - Are const parameters and class variables pessimization?

我试图弄清楚编写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();
}

不,不是。

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

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


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


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

只要逻辑上不更改值或对象,就应将其设置为const 从逻辑上讲,我并不是指每次在技术上都允许您这样做,而是每次在您的函数,类和代码的上下文中都是合乎逻辑的。

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

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

传递const引用参数可为您提供引用的性能优势,但同时可确保源对象保持不变,这对用户而言既是不错的文档,又可进行som优化。

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

这也是为什么通过(例如) const_cast (可以丢弃const会导致某些不良行为的原因。 作为示例,请检查以下内容:

#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使用是一个有价值的工具,它可以提高代码的性能和稳定性,但同时(不要忘记)它有助于记录代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM