常量正确性可以提高性能吗?


92

我已经读过很多遍了,在C或C ++代码中强制执行const正确性不仅是关于可维护性的好习惯,而且还可以使您的编译器执行优化。但是,我也读过完全相反的内容,它完全不影响性能。

因此,您是否有一些示例说明const正确性可以帮助您的编译器改善程序性能?


50
常量正确性是关于可维护性的最佳实践之一。如果您的C ++代码不是const正确的,则基本上是一堆废话,等待灾难来临。它无意影响性能。

2
@Neil Butterworth:不幸的是,事实并非如此。
Beta

6
这是一个const使性能有所不同的示例:stackoverflow.com/questions/1121791/…。但是,这本质上是实现质量的问题。const不确定编译器是否可以合法地进行优化,只是发生了当缺少该版本的编译器而无法进行优化时。
史蒂夫·杰索普

3
我非常确定“ morgennebel”在第一句话中漏掉了“仅”字样:“不仅是一种好习惯”,这更有意义。
IanH

2
@IanH是的,我考虑过。但是OP有足够的时间来澄清。我真的被发布问题的人打勾,然后就消失了。

Answers:


77

const正确性不能提高性能,因为const_castmutable都在语言中,并且不允许代码一致地破坏规则。在C ++ 11中,这甚至变得更糟,在C ++ 11中,您的const数据可能例如是的指针std::atomic,这意味着编译器必须尊重其他线程所做的更改。

就是说,对于编译器而言,查看其生成的代码并确定其是否实际写入给定变量并相应地应用优化是微不足道的。

这一切都表示,const正确性是一个很好的事情相对于可维护性。否则,班级的客户可能会破坏班级的内部成员。例如,考虑一下标准std::string::c_str()-如果它不能返回const值,则可以使用字符串的内部缓冲区!

const出于性能原因,请勿使用。出于可维护性原因使用它。


31
“您将可以使用字符串的内部缓冲区来解决问题!” -至关重要的是,您将能够不小心拧入内部缓冲器。导致的编译器错误const是路标,说:“您在做一些愚蠢的事情”。
史蒂夫·杰索普

4
...和const-casts的路标说,“此代码的作者正在尝试做一些聪明的事” ;-)
Steve Jessop 2010年

5
@Steve Jessop-或const-cast是路标,上面写着“我试图将一堆const正确的代码绑定到一个非const正确的代码上,而我无法修复其中任何一个”。我告诉你,这绝不是聪明的,只是令人讨厌。
迈克尔·科恩

7
@Michael-是的,很公平。最初的路标也许不是“您在做愚蠢的事情”,而是“某人在做愚蠢的事情”。
史蒂夫·杰索普

Godbolt和Arduino告诉我const正确性不仅是为了娱乐。
dgrat

31

是的,它可以。

大多数consts纯粹是为了程序员的利益,并不帮助编译器优化,因为将它们抛弃是合法的,因此它们不会告诉编译器任何对优化有用的信息。但是,某些const不能(合法地)丢弃,它们确实为编译器提供了有用的优化信息。

例如,const可以内联对用类型定义的全局变量的访问,而不能内联对没有const类型的全局变量的访问,因为它可能在运行时更改。

https://godbolt.org/g/UEX4NB

C ++:

int foo1 = 1;
const int foo2 = 2;

int get_foo1() {
    return foo1;
}

int get_foo2() {
    return foo2;
}

asm:

foo1:
        .long   1
foo2:
        .long   2
get_foo1():
        push    rbp
        mov     rbp, rsp
        mov     eax, DWORD PTR foo1[rip] ; foo1 must be accessed by address
        pop     rbp
        ret
get_foo2():
        push    rbp
        mov     rbp, rsp
        mov     eax, 2 ; foo2 has been replaced with an immediate 2
        pop     rbp
        ret

实际上,请记住,虽然const可以提高性能,但在大多数情况下不会,虽然不会,但会很明显。的主要用途const不是优化。


史蒂夫·杰索普(Steve Jessop)在对原始问题的评论中举了另一个例子,提出了值得一提的内容。在块作用域内,编译器可以推断变量是否会被突变并相应地进行优化,而与无关const,因为编译器可以看到该变量的所有用法。相反,在上面的示例中,无法预测是否foo1会发生突变,因为可以在其他翻译单元中对其进行修改。我假设一个假设的超级编译器可以分析整个程序,并确定内联访问foo1...是否有效……但是真正的编译器则不能。


@ericcurtin这就是为什么我在答案中没有提到编译器的原因。通常,在发布生成的程序集时,我会确保说明编译器和版本,但这是每个主要的优化编译器都将执行的优化,所以我不想给人以为这是一个编译器所特有的印象。
Praxeolitic

1
@Acorn这是相同的示例,但是带有一个类对象:godbolt.org/z/R-Zfgc。此外,示例中的变量具有外部链接。
Praxeolitic

6

以我的经验,不

对于标量变量,编译器能够确定何时更改值并自行执行必要的优化。

对于数组指针,const正确性不能保证在存在潜在的别名问题时,值实际上是恒定的。因此,编译器不能单独使用const修饰符来执行优化

如果您正在寻找优化,则应考虑__restrict__或使用特殊的函数修饰符/属性:http : //gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.